archastro.platform.v1.resources.solutions

  1# Copyright (c) 2026 ArchAstro Inc. All Rights Reserved.
  2# This file is auto-generated by @archastro/sdk-generator. Do not edit.
  3# Content hash: b18497f24bab
  4
  5from __future__ import annotations
  6
  7import builtins
  8from typing import Any, Required, TypedDict
  9
 10from ...runtime.http_client import HttpClient, SyncHttpClient
 11from ...types.common import (
 12    SolutionDependentsResponse,
 13    SolutionImportResponse,
 14    SolutionInstallResponse,
 15    SolutionListResponse,
 16    SolutionSummary,
 17    SolutionUpgradeResponse,
 18)
 19
 20
 21class SolutionCreateInputSolutionBundleConfigsItem(TypedDict, total=False):
 22    content: Required[str]
 23    "Full text content of the configuration file."
 24    content_type: str | None
 25    'MIME type of the configuration content, e.g. `"application/x-yaml"` or `"application/json"`. `null` if not specified.'
 26    relative_path: Required[str]
 27    "Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation."
 28
 29
 30class SolutionCreateInputSolutionBundleSetupActionsItem(TypedDict, total=False):
 31    depends_on: list[str] | None
 32    "List of other setup action identifiers that must be completed before this action becomes actionable."
 33    description: str | None
 34    "Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided."
 35    kind: Required[str]
 36    'Category of setup step. One of `"env_var"` (configure an environment variable), `"install"` (complete an installation step), `"custom"` (a user-defined action), or `"integration"` (authorize an OAuth-backed MCP server integration).'
 37    params: dict[str, Any] | None
 38    'Kind-specific configuration for the action. For `"env_var"` steps this typically includes `key` and `scope`; for `"install"` steps it includes `installation_kind`; for `"integration"` steps it includes `mcp_server_ref`. Shape varies by `kind`.'
 39    required: bool | None
 40    "When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`."
 41    sort_order: int | None
 42    "Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified."
 43    title: Required[str]
 44    "Short human-readable label displayed in the setup checklist."
 45    verify_config: dict[str, Any] | None
 46    'Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{"type": "secret_present"}`. `null` if no automated verification is configured.'
 47
 48
 49class SolutionCreateInputSolutionBundleSkillsItemFilesItem(TypedDict, total=False):
 50    content: Required[str]
 51    "Full text content of the file."
 52    content_type: str | None
 53    "MIME type of the file content. Defaults to a value inferred from the file extension when omitted."
 54    relative_path: Required[str]
 55    'Path of this file relative to the skill folder root, e.g. `"skills/my-skill/helpers.md"`.'
 56
 57
 58class SolutionCreateInputSolutionBundleSkillsItem(TypedDict, total=False):
 59    content: Required[str]
 60    "Full text content of the `SKILL.md` file."
 61    content_type: str | None
 62    "MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted."
 63    files: list[SolutionCreateInputSolutionBundleSkillsItemFilesItem] | None
 64    "Additional files nested inside the skill folder, each with its own path and content."
 65    relative_path: Required[str]
 66    'Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `"skills/my-skill/SKILL.md"`).'
 67
 68
 69class SolutionCreateInputSolutionBundleSolutionFilesItem(TypedDict, total=False):
 70    content: Required[str]
 71    'Raw content of the file. When `data_encoding` is `"base64"`, this must be a valid base64-encoded string.'
 72    content_type: str | None
 73    "MIME type of the file. Defaults to a value inferred from the file extension when omitted."
 74    data_encoding: str | None
 75    'Encoding of `content`. `"raw"` (default) stores the value verbatim. `"base64"` decodes the value server-side before storage use this to ship binary assets (PDFs, images) through a JSON body.'
 76    relative_path: Required[str]
 77    "Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`)."
 78
 79
 80class SolutionCreateInputSolutionBundleSolution(TypedDict, total=False):
 81    content: Required[str]
 82    "Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations."
 83    content_type: str | None
 84    "MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON."
 85    files: list[SolutionCreateInputSolutionBundleSolutionFilesItem] | None
 86    "Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record."
 87    lookup_key: Required[str]
 88    "Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config."
 89
 90
 91class SolutionCreateInputSolutionBundleTemplate(TypedDict, total=False):
 92    content: Required[str]
 93    "Full text content of the agent template file, typically a YAML document."
 94    content_type: str | None
 95    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
 96    relative_path: Required[str]
 97    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
 98
 99
100class SolutionCreateInputSolutionBundleTemplatesItem(TypedDict, total=False):
101    content: Required[str]
102    "Full text content of the agent template file, typically a YAML document."
103    content_type: str | None
104    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
105    relative_path: Required[str]
106    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
107
108
109class SolutionCreateInputSolutionBundle(TypedDict, total=False):
110    configs: list[SolutionCreateInputSolutionBundleConfigsItem] | None
111    "Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install."
112    lookup_key_prefix: str | None
113    "String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-<install-id>`."
114    lookup_key_suffix: str | None
115    "String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt."
116    setup_actions: list[SolutionCreateInputSolutionBundleSetupActionsItem] | None
117    "Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates."
118    skills: list[SolutionCreateInputSolutionBundleSkillsItem] | None
119    "Skill bundles (root config plus supporting files) that this solution depends on."
120    solution: Required[SolutionCreateInputSolutionBundleSolution]
121    "The solution config to install, including the solution.yaml body and any referenced component files."
122    template: SolutionCreateInputSolutionBundleTemplate | None
123    "Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates."
124    templates: list[SolutionCreateInputSolutionBundleTemplatesItem] | None
125    "Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`."
126
127
128class SolutionCreateInput(TypedDict, total=False):
129    "Import a Solution into the library"
130
131    dry_run: bool | None
132    "When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`."
133    org: str | None
134    "Organization ID (`org_...`) for the import destination scope."
135    solution: str | None
136    "Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`."
137    solution_bundle: SolutionCreateInputSolutionBundle | None
138    "Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`."
139    team: str | None
140    "Team ID (`team_...`) for the import destination scope."
141    user: str | None
142    "User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set."
143    virtual_path_prefix: str | None
144    "Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix."
145
146
147class SolutionInstallInput(TypedDict, total=False):
148    "Install a Solution"
149
150    allow_auto_import: bool | None
151    "When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing."
152    lookup_key: str | None
153    "Lookup key override for the provisioned resource (for example, the Agent's `agent_key`)."
154    lookup_key_suffix: str | None
155    "Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions."
156    name: str | None
157    "Display name override for the provisioned Agent. Ignored for non-Agent Solutions."
158    org: str | None
159    "Organization ID (`org_...`) for the install destination scope."
160    target: str | None
161    "ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources."
162    team: str | None
163    "Team ID (`team_...`) for the install destination scope."
164    template: str | None
165    "Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly."
166    user: str | None
167    "User ID (`usr_...`) for the install destination scope."
168
169
170class SolutionUpgradeInputSolutionBundleConfigsItem(TypedDict, total=False):
171    content: Required[str]
172    "Full text content of the configuration file."
173    content_type: str | None
174    'MIME type of the configuration content, e.g. `"application/x-yaml"` or `"application/json"`. `null` if not specified.'
175    relative_path: Required[str]
176    "Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation."
177
178
179class SolutionUpgradeInputSolutionBundleSetupActionsItem(TypedDict, total=False):
180    depends_on: list[str] | None
181    "List of other setup action identifiers that must be completed before this action becomes actionable."
182    description: str | None
183    "Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided."
184    kind: Required[str]
185    'Category of setup step. One of `"env_var"` (configure an environment variable), `"install"` (complete an installation step), `"custom"` (a user-defined action), or `"integration"` (authorize an OAuth-backed MCP server integration).'
186    params: dict[str, Any] | None
187    'Kind-specific configuration for the action. For `"env_var"` steps this typically includes `key` and `scope`; for `"install"` steps it includes `installation_kind`; for `"integration"` steps it includes `mcp_server_ref`. Shape varies by `kind`.'
188    required: bool | None
189    "When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`."
190    sort_order: int | None
191    "Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified."
192    title: Required[str]
193    "Short human-readable label displayed in the setup checklist."
194    verify_config: dict[str, Any] | None
195    'Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{"type": "secret_present"}`. `null` if no automated verification is configured.'
196
197
198class SolutionUpgradeInputSolutionBundleSkillsItemFilesItem(TypedDict, total=False):
199    content: Required[str]
200    "Full text content of the file."
201    content_type: str | None
202    "MIME type of the file content. Defaults to a value inferred from the file extension when omitted."
203    relative_path: Required[str]
204    'Path of this file relative to the skill folder root, e.g. `"skills/my-skill/helpers.md"`.'
205
206
207class SolutionUpgradeInputSolutionBundleSkillsItem(TypedDict, total=False):
208    content: Required[str]
209    "Full text content of the `SKILL.md` file."
210    content_type: str | None
211    "MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted."
212    files: list[SolutionUpgradeInputSolutionBundleSkillsItemFilesItem] | None
213    "Additional files nested inside the skill folder, each with its own path and content."
214    relative_path: Required[str]
215    'Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `"skills/my-skill/SKILL.md"`).'
216
217
218class SolutionUpgradeInputSolutionBundleSolutionFilesItem(TypedDict, total=False):
219    content: Required[str]
220    'Raw content of the file. When `data_encoding` is `"base64"`, this must be a valid base64-encoded string.'
221    content_type: str | None
222    "MIME type of the file. Defaults to a value inferred from the file extension when omitted."
223    data_encoding: str | None
224    'Encoding of `content`. `"raw"` (default) stores the value verbatim. `"base64"` decodes the value server-side before storage use this to ship binary assets (PDFs, images) through a JSON body.'
225    relative_path: Required[str]
226    "Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`)."
227
228
229class SolutionUpgradeInputSolutionBundleSolution(TypedDict, total=False):
230    content: Required[str]
231    "Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations."
232    content_type: str | None
233    "MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON."
234    files: list[SolutionUpgradeInputSolutionBundleSolutionFilesItem] | None
235    "Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record."
236    lookup_key: Required[str]
237    "Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config."
238
239
240class SolutionUpgradeInputSolutionBundleTemplate(TypedDict, total=False):
241    content: Required[str]
242    "Full text content of the agent template file, typically a YAML document."
243    content_type: str | None
244    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
245    relative_path: Required[str]
246    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
247
248
249class SolutionUpgradeInputSolutionBundleTemplatesItem(TypedDict, total=False):
250    content: Required[str]
251    "Full text content of the agent template file, typically a YAML document."
252    content_type: str | None
253    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
254    relative_path: Required[str]
255    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
256
257
258class SolutionUpgradeInputSolutionBundle(TypedDict, total=False):
259    configs: list[SolutionUpgradeInputSolutionBundleConfigsItem] | None
260    "Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install."
261    lookup_key_prefix: str | None
262    "String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-<install-id>`."
263    lookup_key_suffix: str | None
264    "String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt."
265    setup_actions: list[SolutionUpgradeInputSolutionBundleSetupActionsItem] | None
266    "Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates."
267    skills: list[SolutionUpgradeInputSolutionBundleSkillsItem] | None
268    "Skill bundles (root config plus supporting files) that this solution depends on."
269    solution: Required[SolutionUpgradeInputSolutionBundleSolution]
270    "The solution config to install, including the solution.yaml body and any referenced component files."
271    template: SolutionUpgradeInputSolutionBundleTemplate | None
272    "Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates."
273    templates: list[SolutionUpgradeInputSolutionBundleTemplatesItem] | None
274    "Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`."
275
276
277class SolutionUpgradeInput(TypedDict, total=False):
278    "Upgrade an installed Solution"
279
280    allow_downgrade: bool | None
281    "When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`."
282    dry_run: bool | None
283    "When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`."
284    expected_review_fingerprint: str | None
285    "Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply."
286    org: str | None
287    "Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this."
288    solution_bundle: SolutionUpgradeInputSolutionBundle | None
289    "Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`."
290    target_solution: str | None
291    "Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`."
292
293
294class AsyncSolutionResource:
295    def __init__(self, http: HttpClient):
296        self._http = http
297
298    async def list(
299        self,
300        *,
301        page: int | None = None,
302        page_size: int | None = None,
303        lookup_key: str | None = None,
304        path_prefix: str | None = None,
305        owners: builtins.list[str] | None = None,
306    ) -> SolutionListResponse:
307        """
308        List Solutions
309        Returns a paginated list of Solutions visible to the caller, merging two
310        scopes: app-level Solutions (system-owned rows with no org affiliation,
311        visible to everyone including unauthenticated callers so they can power
312        the public catalog) and org-level Solutions (system-owned rows stamped with
313        the viewer's org ID, included when an authenticated viewer carries an org
314        context). Unauthenticated callers resolve to an app-scoped anonymous viewer
315        and therefore only ever see the app-level scope.
316        Solutions that appear under both scopes are deduplicated by their stable
317        `solution_id` value. The merged entry's `owners` array lists every scope the
318        Solution was found under (`"system"` and/or `"org"`). When the app-level copy
319        has a higher `solution_version` than the org-level copy, the response includes
320        `upgrade_available: true` and `latest_version` so callers can prompt for an
321        upgrade.
322
323        Args:
324            page: Page number to return. Defaults to `1`.
325            page_size: Number of Solutions per page. Defaults to `25`.
326            lookup_key: Filter to the Solution whose `lookup_key` matches exactly.
327            path_prefix: Filter to Solutions whose `virtual_path` starts with this prefix.
328            owners: Restrict results to a subset of owner scopes. Accepted values: `"system"` (app-level Solutions) and `"org"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
329
330        Returns:
331            Paginated list of Solution summaries visible to the caller.
332        """
333        query: dict[str, object] = {}
334        if page is not None:
335            query["page"] = page
336        if page_size is not None:
337            query["page_size"] = page_size
338        if lookup_key is not None:
339            query["lookup_key"] = lookup_key
340        if path_prefix is not None:
341            query["path_prefix"] = path_prefix
342        if owners is not None:
343            query["owners"] = owners
344        return await self._http.request(
345            "/api/v1/solutions",
346            query=query,
347            response_type=SolutionListResponse,
348        )
349
350    async def create(self, input: SolutionCreateInput) -> SolutionImportResponse:
351        """
352        Import a Solution into the library
353        Imports a Solution and its bundled configs (skills, scripts, templates, files)
354        into the library for the target scope. Two mutually exclusive import modes
355        are supported: pass `solution` to re-import an existing system-owned catalog
356        Solution by ID or `lookup_key`, or pass `solution_bundle` to supply a
357        self-contained inline bundle. Exactly one must be present.
358        The operation upserts the bundle in a single transaction. When `dry_run` is
359        `true` the same pipeline runs but the transaction is rolled back no rows are
360        persisted and the response reflects what would have been written. The
361        response shape is the same in both cases: the Solution summary plus
362        `installed_configs` listing each config the import created or would create.
363        Pairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the
364        Solution into the library; install provisions a runtime resource (Agent,
365        AgentRoutine, AgentTool, etc.) from an already-imported Solution.
366
367        Args:
368            input: Request body.
369            input.dry_run: When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`.
370            input.org: Organization ID (`org_...`) for the import destination scope.
371            input.solution: Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`.
372            input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`.
373            input.team: Team ID (`team_...`) for the import destination scope.
374            input.user: User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set.
375            input.virtual_path_prefix: Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix.
376
377        Returns:
378            The imported Solution in summary form, plus `installed_configs` one entry per config the transaction created or would create in `dry_run` mode. `installed_configs` is deprecated; prefer the `solution` summary shape for new integrations.
379        """
380        return await self._http.request(
381            "/api/v1/solutions",
382            method="POST",
383            body=input,
384            response_type=SolutionImportResponse,
385        )
386
387    async def delete(self, solution: str) -> None:
388        """
389        Delete a Solution
390        Permanently deletes an imported Solution and all configs bundled with it,
391        including templates, skills, scripts, and files. The deletion runs in a
392        single transaction; provider-stored blobs are swept asynchronously after commit.
393        Org-scope callers (for example, an org admin in the Library settings page) can
394        only delete their org's copy of the Solution. App-scope callers can delete
395        Solutions at either scope. RBAC is enforced inside the core delete flow.
396        Returns `204 No Content` on success.
397
398        Args:
399            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to delete.
400
401        Returns:
402            Empty body. HTTP 204 indicates the Solution was deleted successfully.
403        """
404        await self._http.request(f"/api/v1/solutions/{solution}", method="DELETE")
405
406    async def get(self, solution: str) -> SolutionSummary:
407        """
408        Retrieve a Solution
409        Returns a single Solution identified by its config ID (`cfg_...`) or
410        `lookup_key`, in the same summary shape the list endpoint emits. The response
411        always includes a freshly-minted `readme_url` call this endpoint to refresh
412        an expired README token without making any other state change.
413        Visibility matches the list endpoint: app-level Solutions (no org affiliation)
414        are visible to everyone including unauthenticated callers, so the public
415        catalog can render a Solution's detail page logged-out; org-scoped Solutions
416        are only visible to authenticated viewers whose org context matches. Anything
417        else returns 404.
418        When the resolved Solution is org-scoped, the endpoint compares its
419        `solution_version` against the matching app-level copy. If the app-level copy
420        is at a higher version the response includes `upgrade_available: true` and
421        `latest_version`. App-level resolutions always report `upgrade_available: false`.
422
423        Args:
424            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to retrieve.
425
426        Returns:
427            Solution summary including a freshly-minted `readme_url` token valid for one hour.
428        """
429        return await self._http.request(
430            f"/api/v1/solutions/{solution}",
431            response_type=SolutionSummary,
432        )
433
434    async def dependents(self, solution: str) -> SolutionDependentsResponse:
435        """
436        Preview Solution delete impact
437        Returns a read-only preview of what deleting the specified Solution would
438        affect: the agents that reference the Solution's bundle, and the count of
439        bundled configs that would be orphaned rather than cascade-deleted.
440        Use this endpoint before calling `DELETE /api/v1/solutions/:solution` to
441        surface a warning when live agents depend on the Solution.
442        Visibility scope mirrors the delete endpoint: org-scope viewers see their
443        org's copy; app-scope viewers can inspect either scope.
444
445        Args:
446            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to inspect.
447
448        Returns:
449            Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.
450        """
451        return await self._http.request(
452            f"/api/v1/solutions/{solution}/dependents",
453            response_type=SolutionDependentsResponse,
454        )
455
456    async def install(self, solution: str, input: SolutionInstallInput) -> SolutionInstallResponse:
457        """
458        Install a Solution
459        Provisions a runtime resource from an already-imported Solution. The type of
460        resource created depends on the template the Solution wraps: an
461        `AgentTemplate` produces an Agent, an `AutomationTemplate` produces an
462        Automation, and attachment templates (`AgentRoutineTemplate`,
463        `AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a
464        sub-resource to an existing Agent specified by `target`.
465        For Solutions that bundle more than one template, pass `template` (the ID or
466        `lookup_key` of the desired template) to select which one to provision.
467        Single-template Solutions do not require `template`.
468        Pairs with `POST /api/v1/solutions` (import): import puts the Solution into
469        the library; install provisions a runtime resource from it.
470
471        Args:
472            solution: Config ID (`cfg_...`) or `lookup_key` of the already-imported Solution to install from.
473            input: Request body.
474            input.allow_auto_import: When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing.
475            input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's `agent_key`).
476            input.lookup_key_suffix: Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
477            input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
478            input.org: Organization ID (`org_...`) for the install destination scope.
479            input.target: ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources.
480            input.team: Team ID (`team_...`) for the install destination scope.
481            input.template: Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
482            input.user: User ID (`usr_...`) for the install destination scope.
483
484        Returns:
485            The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.
486        """
487        return await self._http.request(
488            f"/api/v1/solutions/{solution}/install",
489            method="POST",
490            body=input,
491            response_type=SolutionInstallResponse,
492        )
493
494    async def readme(self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
495        """
496        Retrieve a Solution README or asset
497        Serves the README markdown or a bundled asset for an imported Solution. Both
498        modes use the same path and require a short-lived signed `token` in the query
499        string rather than an `Authorization` header, so browsers can load asset URLs
500        directly from `<img src>` attributes without custom request logic.
501        When `file` is omitted the response is the Solution's `readme` field rendered
502        as `text/markdown`. All local asset references in the markdown are rewritten to
503        point back at this endpoint with `?file=PATH&token=TOKEN` so browsers can load
504        images inline without additional authentication.
505        When `file` is set the response is the raw bytes of the matching asset (a File
506        child whose `relative_path` equals `PATH`, or an inline `assets` entry by
507        name) with the asset's stored `Content-Type`.
508        Tokens are scoped to a single Solution, carry the viewer's app, org, and
509        sandbox context from the time they were minted, and expire after one hour.
510        Obtain a fresh token by calling `GET /api/v1/solutions/:solution`, which
511        always returns a newly minted `readme_url`.
512
513        Args:
514            solution: Solution config ID (`cfg_...`) identifying the Solution whose README or asset to retrieve.
515            token: Signed URL token minted by the list or show endpoint. Expires after one hour.
516            file: Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown.
517
518        Returns:
519            README markdown (`text/markdown`) when `file` is omitted, or the raw asset bytes with the asset's `Content-Type` when `file` is set.
520        """
521        query: dict[str, object] = {}
522        query["token"] = token
523        if file is not None:
524            query["file"] = file
525        return await self._http.request_raw(f"/api/v1/solutions/{solution}/readme", query=query)
526
527    async def upgrade(self, solution: str, input: SolutionUpgradeInput) -> SolutionUpgradeResponse:
528        """
529        Upgrade an installed Solution
530        Applies an incoming bundle to an already-installed Solution in a single atomic
531        transaction, bringing its configs in line with the new bundle. Config IDs are
532        preserved across the upgrade. Configs that existed in the old bundle but are
533        absent from the new one are orphaned (top-level) or hard-deleted (child rows).
534        Two mutually exclusive source modes: pass `target_solution` to pull the
535        incoming bundle from an existing Solution by ID or `lookup_key`, or pass
536        `solution_bundle` to supply a complete inline bundle directly. Exactly one
537        must be present.
538        When `dry_run` is `true` the full diff is computed and returned but no
539        changes are written. Pass the dry-run response's `review_fingerprint` as
540        `expected_review_fingerprint` when applying to guard against the bundle
541        changing between review and apply.
542
543        Args:
544            solution: Config ID (`cfg_...`) or `lookup_key` of the currently installed Solution to upgrade.
545            input: Request body.
546            input.allow_downgrade: When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`.
547            input.dry_run: When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`.
548            input.expected_review_fingerprint: Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply.
549            input.org: Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this.
550            input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`.
551            input.target_solution: Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`.
552
553        Returns:
554            Updated Solution plus the full upgrade diff.
555        """
556        return await self._http.request(
557            f"/api/v1/solutions/{solution}/upgrade",
558            method="POST",
559            body=input,
560            response_type=SolutionUpgradeResponse,
561        )
562
563
564class SolutionResource:
565    def __init__(self, http: SyncHttpClient):
566        self._http = http
567
568    def list(
569        self,
570        *,
571        page: int | None = None,
572        page_size: int | None = None,
573        lookup_key: str | None = None,
574        path_prefix: str | None = None,
575        owners: builtins.list[str] | None = None,
576    ) -> SolutionListResponse:
577        """
578        List Solutions
579        Returns a paginated list of Solutions visible to the caller, merging two
580        scopes: app-level Solutions (system-owned rows with no org affiliation,
581        visible to everyone including unauthenticated callers so they can power
582        the public catalog) and org-level Solutions (system-owned rows stamped with
583        the viewer's org ID, included when an authenticated viewer carries an org
584        context). Unauthenticated callers resolve to an app-scoped anonymous viewer
585        and therefore only ever see the app-level scope.
586        Solutions that appear under both scopes are deduplicated by their stable
587        `solution_id` value. The merged entry's `owners` array lists every scope the
588        Solution was found under (`"system"` and/or `"org"`). When the app-level copy
589        has a higher `solution_version` than the org-level copy, the response includes
590        `upgrade_available: true` and `latest_version` so callers can prompt for an
591        upgrade.
592
593        Args:
594            page: Page number to return. Defaults to `1`.
595            page_size: Number of Solutions per page. Defaults to `25`.
596            lookup_key: Filter to the Solution whose `lookup_key` matches exactly.
597            path_prefix: Filter to Solutions whose `virtual_path` starts with this prefix.
598            owners: Restrict results to a subset of owner scopes. Accepted values: `"system"` (app-level Solutions) and `"org"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
599
600        Returns:
601            Paginated list of Solution summaries visible to the caller.
602        """
603        query: dict[str, object] = {}
604        if page is not None:
605            query["page"] = page
606        if page_size is not None:
607            query["page_size"] = page_size
608        if lookup_key is not None:
609            query["lookup_key"] = lookup_key
610        if path_prefix is not None:
611            query["path_prefix"] = path_prefix
612        if owners is not None:
613            query["owners"] = owners
614        return self._http.request(
615            "/api/v1/solutions",
616            query=query,
617            response_type=SolutionListResponse,
618        )
619
620    def create(self, input: SolutionCreateInput) -> SolutionImportResponse:
621        """
622        Import a Solution into the library
623        Imports a Solution and its bundled configs (skills, scripts, templates, files)
624        into the library for the target scope. Two mutually exclusive import modes
625        are supported: pass `solution` to re-import an existing system-owned catalog
626        Solution by ID or `lookup_key`, or pass `solution_bundle` to supply a
627        self-contained inline bundle. Exactly one must be present.
628        The operation upserts the bundle in a single transaction. When `dry_run` is
629        `true` the same pipeline runs but the transaction is rolled back no rows are
630        persisted and the response reflects what would have been written. The
631        response shape is the same in both cases: the Solution summary plus
632        `installed_configs` listing each config the import created or would create.
633        Pairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the
634        Solution into the library; install provisions a runtime resource (Agent,
635        AgentRoutine, AgentTool, etc.) from an already-imported Solution.
636
637        Args:
638            input: Request body.
639            input.dry_run: When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`.
640            input.org: Organization ID (`org_...`) for the import destination scope.
641            input.solution: Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`.
642            input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`.
643            input.team: Team ID (`team_...`) for the import destination scope.
644            input.user: User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set.
645            input.virtual_path_prefix: Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix.
646
647        Returns:
648            The imported Solution in summary form, plus `installed_configs` one entry per config the transaction created or would create in `dry_run` mode. `installed_configs` is deprecated; prefer the `solution` summary shape for new integrations.
649        """
650        return self._http.request(
651            "/api/v1/solutions",
652            method="POST",
653            body=input,
654            response_type=SolutionImportResponse,
655        )
656
657    def delete(self, solution: str) -> None:
658        """
659        Delete a Solution
660        Permanently deletes an imported Solution and all configs bundled with it,
661        including templates, skills, scripts, and files. The deletion runs in a
662        single transaction; provider-stored blobs are swept asynchronously after commit.
663        Org-scope callers (for example, an org admin in the Library settings page) can
664        only delete their org's copy of the Solution. App-scope callers can delete
665        Solutions at either scope. RBAC is enforced inside the core delete flow.
666        Returns `204 No Content` on success.
667
668        Args:
669            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to delete.
670
671        Returns:
672            Empty body. HTTP 204 indicates the Solution was deleted successfully.
673        """
674        self._http.request(f"/api/v1/solutions/{solution}", method="DELETE")
675
676    def get(self, solution: str) -> SolutionSummary:
677        """
678        Retrieve a Solution
679        Returns a single Solution identified by its config ID (`cfg_...`) or
680        `lookup_key`, in the same summary shape the list endpoint emits. The response
681        always includes a freshly-minted `readme_url` call this endpoint to refresh
682        an expired README token without making any other state change.
683        Visibility matches the list endpoint: app-level Solutions (no org affiliation)
684        are visible to everyone including unauthenticated callers, so the public
685        catalog can render a Solution's detail page logged-out; org-scoped Solutions
686        are only visible to authenticated viewers whose org context matches. Anything
687        else returns 404.
688        When the resolved Solution is org-scoped, the endpoint compares its
689        `solution_version` against the matching app-level copy. If the app-level copy
690        is at a higher version the response includes `upgrade_available: true` and
691        `latest_version`. App-level resolutions always report `upgrade_available: false`.
692
693        Args:
694            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to retrieve.
695
696        Returns:
697            Solution summary including a freshly-minted `readme_url` token valid for one hour.
698        """
699        return self._http.request(f"/api/v1/solutions/{solution}", response_type=SolutionSummary)
700
701    def dependents(self, solution: str) -> SolutionDependentsResponse:
702        """
703        Preview Solution delete impact
704        Returns a read-only preview of what deleting the specified Solution would
705        affect: the agents that reference the Solution's bundle, and the count of
706        bundled configs that would be orphaned rather than cascade-deleted.
707        Use this endpoint before calling `DELETE /api/v1/solutions/:solution` to
708        surface a warning when live agents depend on the Solution.
709        Visibility scope mirrors the delete endpoint: org-scope viewers see their
710        org's copy; app-scope viewers can inspect either scope.
711
712        Args:
713            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to inspect.
714
715        Returns:
716            Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.
717        """
718        return self._http.request(
719            f"/api/v1/solutions/{solution}/dependents",
720            response_type=SolutionDependentsResponse,
721        )
722
723    def install(self, solution: str, input: SolutionInstallInput) -> SolutionInstallResponse:
724        """
725        Install a Solution
726        Provisions a runtime resource from an already-imported Solution. The type of
727        resource created depends on the template the Solution wraps: an
728        `AgentTemplate` produces an Agent, an `AutomationTemplate` produces an
729        Automation, and attachment templates (`AgentRoutineTemplate`,
730        `AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a
731        sub-resource to an existing Agent specified by `target`.
732        For Solutions that bundle more than one template, pass `template` (the ID or
733        `lookup_key` of the desired template) to select which one to provision.
734        Single-template Solutions do not require `template`.
735        Pairs with `POST /api/v1/solutions` (import): import puts the Solution into
736        the library; install provisions a runtime resource from it.
737
738        Args:
739            solution: Config ID (`cfg_...`) or `lookup_key` of the already-imported Solution to install from.
740            input: Request body.
741            input.allow_auto_import: When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing.
742            input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's `agent_key`).
743            input.lookup_key_suffix: Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
744            input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
745            input.org: Organization ID (`org_...`) for the install destination scope.
746            input.target: ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources.
747            input.team: Team ID (`team_...`) for the install destination scope.
748            input.template: Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
749            input.user: User ID (`usr_...`) for the install destination scope.
750
751        Returns:
752            The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.
753        """
754        return self._http.request(
755            f"/api/v1/solutions/{solution}/install",
756            method="POST",
757            body=input,
758            response_type=SolutionInstallResponse,
759        )
760
761    def readme(self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
762        """
763        Retrieve a Solution README or asset
764        Serves the README markdown or a bundled asset for an imported Solution. Both
765        modes use the same path and require a short-lived signed `token` in the query
766        string rather than an `Authorization` header, so browsers can load asset URLs
767        directly from `<img src>` attributes without custom request logic.
768        When `file` is omitted the response is the Solution's `readme` field rendered
769        as `text/markdown`. All local asset references in the markdown are rewritten to
770        point back at this endpoint with `?file=PATH&token=TOKEN` so browsers can load
771        images inline without additional authentication.
772        When `file` is set the response is the raw bytes of the matching asset (a File
773        child whose `relative_path` equals `PATH`, or an inline `assets` entry by
774        name) with the asset's stored `Content-Type`.
775        Tokens are scoped to a single Solution, carry the viewer's app, org, and
776        sandbox context from the time they were minted, and expire after one hour.
777        Obtain a fresh token by calling `GET /api/v1/solutions/:solution`, which
778        always returns a newly minted `readme_url`.
779
780        Args:
781            solution: Solution config ID (`cfg_...`) identifying the Solution whose README or asset to retrieve.
782            token: Signed URL token minted by the list or show endpoint. Expires after one hour.
783            file: Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown.
784
785        Returns:
786            README markdown (`text/markdown`) when `file` is omitted, or the raw asset bytes with the asset's `Content-Type` when `file` is set.
787        """
788        query: dict[str, object] = {}
789        query["token"] = token
790        if file is not None:
791            query["file"] = file
792        return self._http.request_raw(f"/api/v1/solutions/{solution}/readme", query=query)
793
794    def upgrade(self, solution: str, input: SolutionUpgradeInput) -> SolutionUpgradeResponse:
795        """
796        Upgrade an installed Solution
797        Applies an incoming bundle to an already-installed Solution in a single atomic
798        transaction, bringing its configs in line with the new bundle. Config IDs are
799        preserved across the upgrade. Configs that existed in the old bundle but are
800        absent from the new one are orphaned (top-level) or hard-deleted (child rows).
801        Two mutually exclusive source modes: pass `target_solution` to pull the
802        incoming bundle from an existing Solution by ID or `lookup_key`, or pass
803        `solution_bundle` to supply a complete inline bundle directly. Exactly one
804        must be present.
805        When `dry_run` is `true` the full diff is computed and returned but no
806        changes are written. Pass the dry-run response's `review_fingerprint` as
807        `expected_review_fingerprint` when applying to guard against the bundle
808        changing between review and apply.
809
810        Args:
811            solution: Config ID (`cfg_...`) or `lookup_key` of the currently installed Solution to upgrade.
812            input: Request body.
813            input.allow_downgrade: When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`.
814            input.dry_run: When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`.
815            input.expected_review_fingerprint: Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply.
816            input.org: Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this.
817            input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`.
818            input.target_solution: Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`.
819
820        Returns:
821            Updated Solution plus the full upgrade diff.
822        """
823        return self._http.request(
824            f"/api/v1/solutions/{solution}/upgrade",
825            method="POST",
826            body=input,
827            response_type=SolutionUpgradeResponse,
828        )
class SolutionCreateInputSolutionBundleConfigsItem(typing.TypedDict):
22class SolutionCreateInputSolutionBundleConfigsItem(TypedDict, total=False):
23    content: Required[str]
24    "Full text content of the configuration file."
25    content_type: str | None
26    'MIME type of the configuration content, e.g. `"application/x-yaml"` or `"application/json"`. `null` if not specified.'
27    relative_path: Required[str]
28    "Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation."
content: Required[str]

Full text content of the configuration file.

content_type: str | None

MIME type of the configuration content, e.g. "application/x-yaml" or "application/json". null if not specified.

relative_path: Required[str]

Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation.

class SolutionCreateInputSolutionBundleSetupActionsItem(typing.TypedDict):
31class SolutionCreateInputSolutionBundleSetupActionsItem(TypedDict, total=False):
32    depends_on: list[str] | None
33    "List of other setup action identifiers that must be completed before this action becomes actionable."
34    description: str | None
35    "Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided."
36    kind: Required[str]
37    'Category of setup step. One of `"env_var"` (configure an environment variable), `"install"` (complete an installation step), `"custom"` (a user-defined action), or `"integration"` (authorize an OAuth-backed MCP server integration).'
38    params: dict[str, Any] | None
39    'Kind-specific configuration for the action. For `"env_var"` steps this typically includes `key` and `scope`; for `"install"` steps it includes `installation_kind`; for `"integration"` steps it includes `mcp_server_ref`. Shape varies by `kind`.'
40    required: bool | None
41    "When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`."
42    sort_order: int | None
43    "Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified."
44    title: Required[str]
45    "Short human-readable label displayed in the setup checklist."
46    verify_config: dict[str, Any] | None
47    'Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{"type": "secret_present"}`. `null` if no automated verification is configured.'
depends_on: list[str] | None

List of other setup action identifiers that must be completed before this action becomes actionable.

description: str | None

Markdown-formatted instructions or context shown beneath the checklist item. null if not provided.

kind: Required[str]

Category of setup step. One of "env_var" (configure an environment variable), "install" (complete an installation step), "custom" (a user-defined action), or "integration" (authorize an OAuth-backed MCP server integration).

params: dict[str, typing.Any] | None

Kind-specific configuration for the action. For "env_var" steps this typically includes key and scope; for "install" steps it includes installation_kind; for "integration" steps it includes mcp_server_ref. Shape varies by kind.

required: bool | None

When true, this action must be completed before the checklist progress bar reaches 100%. Defaults to true.

sort_order: int | None

Numeric sort position controlling the display order of this action in the checklist. Defaults to 0 when not specified.

title: Required[str]

Short human-readable label displayed in the setup checklist.

verify_config: dict[str, typing.Any] | None

Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. {"type": "secret_present"}. null if no automated verification is configured.

class SolutionCreateInputSolutionBundleSkillsItemFilesItem(typing.TypedDict):
50class SolutionCreateInputSolutionBundleSkillsItemFilesItem(TypedDict, total=False):
51    content: Required[str]
52    "Full text content of the file."
53    content_type: str | None
54    "MIME type of the file content. Defaults to a value inferred from the file extension when omitted."
55    relative_path: Required[str]
56    'Path of this file relative to the skill folder root, e.g. `"skills/my-skill/helpers.md"`.'
content: Required[str]

Full text content of the file.

content_type: str | None

MIME type of the file content. Defaults to a value inferred from the file extension when omitted.

relative_path: Required[str]

Path of this file relative to the skill folder root, e.g. "skills/my-skill/helpers.md".

class SolutionCreateInputSolutionBundleSkillsItem(typing.TypedDict):
59class SolutionCreateInputSolutionBundleSkillsItem(TypedDict, total=False):
60    content: Required[str]
61    "Full text content of the `SKILL.md` file."
62    content_type: str | None
63    "MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted."
64    files: list[SolutionCreateInputSolutionBundleSkillsItemFilesItem] | None
65    "Additional files nested inside the skill folder, each with its own path and content."
66    relative_path: Required[str]
67    'Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `"skills/my-skill/SKILL.md"`).'
content: Required[str]

Full text content of the SKILL.md file.

content_type: str | None

MIME type of the SKILL.md content. Defaults to text/markdown when omitted.

Additional files nested inside the skill folder, each with its own path and content.

relative_path: Required[str]

Bundle-relative path to the skill root, which must end in /SKILL.md (e.g. "skills/my-skill/SKILL.md").

class SolutionCreateInputSolutionBundleSolutionFilesItem(typing.TypedDict):
70class SolutionCreateInputSolutionBundleSolutionFilesItem(TypedDict, total=False):
71    content: Required[str]
72    'Raw content of the file. When `data_encoding` is `"base64"`, this must be a valid base64-encoded string.'
73    content_type: str | None
74    "MIME type of the file. Defaults to a value inferred from the file extension when omitted."
75    data_encoding: str | None
76    'Encoding of `content`. `"raw"` (default) stores the value verbatim. `"base64"` decodes the value server-side before storage use this to ship binary assets (PDFs, images) through a JSON body.'
77    relative_path: Required[str]
78    "Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`)."
content: Required[str]

Raw content of the file. When data_encoding is "base64", this must be a valid base64-encoded string.

content_type: str | None

MIME type of the file. Defaults to a value inferred from the file extension when omitted.

data_encoding: str | None

Encoding of content. "raw" (default) stores the value verbatim. "base64" decodes the value server-side before storage use this to ship binary assets (PDFs, images) through a JSON body.

relative_path: Required[str]

Path of this file relative to the solution root (e.g. README.md, assets/diagram.png).

class SolutionCreateInputSolutionBundleSolution(typing.TypedDict):
81class SolutionCreateInputSolutionBundleSolution(TypedDict, total=False):
82    content: Required[str]
83    "Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations."
84    content_type: str | None
85    "MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON."
86    files: list[SolutionCreateInputSolutionBundleSolutionFilesItem] | None
87    "Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record."
88    lookup_key: Required[str]
89    "Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config."
content: Required[str]

Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations.

content_type: str | None

MIME type of content. Defaults to application/x-yaml; pass application/json when submitting JSON.

Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via path:// URIs. Each entry is persisted as a child file record.

lookup_key: Required[str]

Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config.

class SolutionCreateInputSolutionBundleTemplate(typing.TypedDict):
92class SolutionCreateInputSolutionBundleTemplate(TypedDict, total=False):
93    content: Required[str]
94    "Full text content of the agent template file, typically a YAML document."
95    content_type: str | None
96    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
97    relative_path: Required[str]
98    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
content: Required[str]

Full text content of the agent template file, typically a YAML document.

content_type: str | None

MIME type of the template content. Defaults to application/x-yaml when omitted.

relative_path: Required[str]

Bundle-relative path to the template file, used to derive its storage identity (e.g. "agent.yaml").

class SolutionCreateInputSolutionBundleTemplatesItem(typing.TypedDict):
101class SolutionCreateInputSolutionBundleTemplatesItem(TypedDict, total=False):
102    content: Required[str]
103    "Full text content of the agent template file, typically a YAML document."
104    content_type: str | None
105    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
106    relative_path: Required[str]
107    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
content: Required[str]

Full text content of the agent template file, typically a YAML document.

content_type: str | None

MIME type of the template content. Defaults to application/x-yaml when omitted.

relative_path: Required[str]

Bundle-relative path to the template file, used to derive its storage identity (e.g. "agent.yaml").

class SolutionCreateInputSolutionBundle(typing.TypedDict):
110class SolutionCreateInputSolutionBundle(TypedDict, total=False):
111    configs: list[SolutionCreateInputSolutionBundleConfigsItem] | None
112    "Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install."
113    lookup_key_prefix: str | None
114    "String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-<install-id>`."
115    lookup_key_suffix: str | None
116    "String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt."
117    setup_actions: list[SolutionCreateInputSolutionBundleSetupActionsItem] | None
118    "Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates."
119    skills: list[SolutionCreateInputSolutionBundleSkillsItem] | None
120    "Skill bundles (root config plus supporting files) that this solution depends on."
121    solution: Required[SolutionCreateInputSolutionBundleSolution]
122    "The solution config to install, including the solution.yaml body and any referenced component files."
123    template: SolutionCreateInputSolutionBundleTemplate | None
124    "Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates."
125    templates: list[SolutionCreateInputSolutionBundleTemplatesItem] | None
126    "Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`."

Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install.

lookup_key_prefix: str | None

String prepended (with a - separator) to every uploaded config's lookup_key and every path:// reference in the solution body. Typical value is solutions-<install-id>.

lookup_key_suffix: str | None

String appended to every uploaded config's lookup_key and every path:// reference in the solution body. Should be stable for a given install and unique per attempt.

Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own setup_actions. Omit when bundling multiple templates.

Skill bundles (root config plus supporting files) that this solution depends on.

The solution config to install, including the solution.yaml body and any referenced component files.

Convenience shorthand for supplying a single template. Equivalent to setting templates: [template]. Mutually exclusive with templates. Use templates directly when bundling multiple sibling templates.

Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via template_path:. Mutually exclusive with template.

class SolutionCreateInput(typing.TypedDict):
129class SolutionCreateInput(TypedDict, total=False):
130    "Import a Solution into the library"
131
132    dry_run: bool | None
133    "When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`."
134    org: str | None
135    "Organization ID (`org_...`) for the import destination scope."
136    solution: str | None
137    "Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`."
138    solution_bundle: SolutionCreateInputSolutionBundle | None
139    "Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`."
140    team: str | None
141    "Team ID (`team_...`) for the import destination scope."
142    user: str | None
143    "User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set."
144    virtual_path_prefix: str | None
145    "Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix."

Import a Solution into the library

dry_run: bool | None

When true, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to false.

org: str | None

Organization ID (org_...) for the import destination scope.

solution: str | None

Config ID (cfg_...) or lookup_key of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with solution_bundle.

solution_bundle: SolutionCreateInputSolutionBundle | None

Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with solution.

team: str | None

Team ID (team_...) for the import destination scope.

user: str | None

User ID (usr_...) for the import destination scope. Only one of org, team, or user may be set.

virtual_path_prefix: str | None

Path prefix under which all uploaded configs' virtual_path values are anchored (for example solutions/<uuid>). Stable per install; omit to use no prefix.

class SolutionInstallInput(typing.TypedDict):
148class SolutionInstallInput(TypedDict, total=False):
149    "Install a Solution"
150
151    allow_auto_import: bool | None
152    "When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing."
153    lookup_key: str | None
154    "Lookup key override for the provisioned resource (for example, the Agent's `agent_key`)."
155    lookup_key_suffix: str | None
156    "Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions."
157    name: str | None
158    "Display name override for the provisioned Agent. Ignored for non-Agent Solutions."
159    org: str | None
160    "Organization ID (`org_...`) for the install destination scope."
161    target: str | None
162    "ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources."
163    team: str | None
164    "Team ID (`team_...`) for the install destination scope."
165    template: str | None
166    "Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly."
167    user: str | None
168    "User ID (`usr_...`) for the install destination scope."

Install a Solution

allow_auto_import: bool | None

When true, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit org param. Defaults to false; without it the endpoint returns 404 when the org-scoped Solution is missing.

lookup_key: str | None

Lookup key override for the provisioned resource (for example, the Agent's agent_key).

lookup_key_suffix: str | None

Suffix appended to every config_ref: resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.

name: str | None

Display name override for the provisioned Agent. Ignored for non-Agent Solutions.

org: str | None

Organization ID (org_...) for the install destination scope.

target: str | None

ID or lookup_key of the parent Agent to attach to. Required when installing an AgentRoutineTemplate, AgentToolTemplate, AgentSkillTemplate, or AgentComputerTemplate Solution, since those produce sub-resources attached to an existing Agent. Omit for AgentTemplate and AutomationTemplate Solutions, which provision standalone resources.

team: str | None

Team ID (team_...) for the install destination scope.

template: str | None

Config ID (cfg_...) or lookup_key of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.

user: str | None

User ID (usr_...) for the install destination scope.

class SolutionUpgradeInputSolutionBundleConfigsItem(typing.TypedDict):
171class SolutionUpgradeInputSolutionBundleConfigsItem(TypedDict, total=False):
172    content: Required[str]
173    "Full text content of the configuration file."
174    content_type: str | None
175    'MIME type of the configuration content, e.g. `"application/x-yaml"` or `"application/json"`. `null` if not specified.'
176    relative_path: Required[str]
177    "Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation."
content: Required[str]

Full text content of the configuration file.

content_type: str | None

MIME type of the configuration content, e.g. "application/x-yaml" or "application/json". null if not specified.

relative_path: Required[str]

Bundle-relative path to this config file. The path determines the config kind and its storage identity within the installation.

class SolutionUpgradeInputSolutionBundleSetupActionsItem(typing.TypedDict):
180class SolutionUpgradeInputSolutionBundleSetupActionsItem(TypedDict, total=False):
181    depends_on: list[str] | None
182    "List of other setup action identifiers that must be completed before this action becomes actionable."
183    description: str | None
184    "Markdown-formatted instructions or context shown beneath the checklist item. `null` if not provided."
185    kind: Required[str]
186    'Category of setup step. One of `"env_var"` (configure an environment variable), `"install"` (complete an installation step), `"custom"` (a user-defined action), or `"integration"` (authorize an OAuth-backed MCP server integration).'
187    params: dict[str, Any] | None
188    'Kind-specific configuration for the action. For `"env_var"` steps this typically includes `key` and `scope`; for `"install"` steps it includes `installation_kind`; for `"integration"` steps it includes `mcp_server_ref`. Shape varies by `kind`.'
189    required: bool | None
190    "When `true`, this action must be completed before the checklist progress bar reaches 100%. Defaults to `true`."
191    sort_order: int | None
192    "Numeric sort position controlling the display order of this action in the checklist. Defaults to `0` when not specified."
193    title: Required[str]
194    "Short human-readable label displayed in the setup checklist."
195    verify_config: dict[str, Any] | None
196    'Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. `{"type": "secret_present"}`. `null` if no automated verification is configured.'
depends_on: list[str] | None

List of other setup action identifiers that must be completed before this action becomes actionable.

description: str | None

Markdown-formatted instructions or context shown beneath the checklist item. null if not provided.

kind: Required[str]

Category of setup step. One of "env_var" (configure an environment variable), "install" (complete an installation step), "custom" (a user-defined action), or "integration" (authorize an OAuth-backed MCP server integration).

params: dict[str, typing.Any] | None

Kind-specific configuration for the action. For "env_var" steps this typically includes key and scope; for "install" steps it includes installation_kind; for "integration" steps it includes mcp_server_ref. Shape varies by kind.

required: bool | None

When true, this action must be completed before the checklist progress bar reaches 100%. Defaults to true.

sort_order: int | None

Numeric sort position controlling the display order of this action in the checklist. Defaults to 0 when not specified.

title: Required[str]

Short human-readable label displayed in the setup checklist.

verify_config: dict[str, typing.Any] | None

Configuration passed to the runtime verifier to determine whether the action has been completed, e.g. {"type": "secret_present"}. null if no automated verification is configured.

class SolutionUpgradeInputSolutionBundleSkillsItemFilesItem(typing.TypedDict):
199class SolutionUpgradeInputSolutionBundleSkillsItemFilesItem(TypedDict, total=False):
200    content: Required[str]
201    "Full text content of the file."
202    content_type: str | None
203    "MIME type of the file content. Defaults to a value inferred from the file extension when omitted."
204    relative_path: Required[str]
205    'Path of this file relative to the skill folder root, e.g. `"skills/my-skill/helpers.md"`.'
content: Required[str]

Full text content of the file.

content_type: str | None

MIME type of the file content. Defaults to a value inferred from the file extension when omitted.

relative_path: Required[str]

Path of this file relative to the skill folder root, e.g. "skills/my-skill/helpers.md".

class SolutionUpgradeInputSolutionBundleSkillsItem(typing.TypedDict):
208class SolutionUpgradeInputSolutionBundleSkillsItem(TypedDict, total=False):
209    content: Required[str]
210    "Full text content of the `SKILL.md` file."
211    content_type: str | None
212    "MIME type of the `SKILL.md` content. Defaults to `text/markdown` when omitted."
213    files: list[SolutionUpgradeInputSolutionBundleSkillsItemFilesItem] | None
214    "Additional files nested inside the skill folder, each with its own path and content."
215    relative_path: Required[str]
216    'Bundle-relative path to the skill root, which must end in `/SKILL.md` (e.g. `"skills/my-skill/SKILL.md"`).'
content: Required[str]

Full text content of the SKILL.md file.

content_type: str | None

MIME type of the SKILL.md content. Defaults to text/markdown when omitted.

Additional files nested inside the skill folder, each with its own path and content.

relative_path: Required[str]

Bundle-relative path to the skill root, which must end in /SKILL.md (e.g. "skills/my-skill/SKILL.md").

class SolutionUpgradeInputSolutionBundleSolutionFilesItem(typing.TypedDict):
219class SolutionUpgradeInputSolutionBundleSolutionFilesItem(TypedDict, total=False):
220    content: Required[str]
221    'Raw content of the file. When `data_encoding` is `"base64"`, this must be a valid base64-encoded string.'
222    content_type: str | None
223    "MIME type of the file. Defaults to a value inferred from the file extension when omitted."
224    data_encoding: str | None
225    'Encoding of `content`. `"raw"` (default) stores the value verbatim. `"base64"` decodes the value server-side before storage use this to ship binary assets (PDFs, images) through a JSON body.'
226    relative_path: Required[str]
227    "Path of this file relative to the solution root (e.g. `README.md`, `assets/diagram.png`)."
content: Required[str]

Raw content of the file. When data_encoding is "base64", this must be a valid base64-encoded string.

content_type: str | None

MIME type of the file. Defaults to a value inferred from the file extension when omitted.

data_encoding: str | None

Encoding of content. "raw" (default) stores the value verbatim. "base64" decodes the value server-side before storage use this to ship binary assets (PDFs, images) through a JSON body.

relative_path: Required[str]

Path of this file relative to the solution root (e.g. README.md, assets/diagram.png).

class SolutionUpgradeInputSolutionBundleSolution(typing.TypedDict):
230class SolutionUpgradeInputSolutionBundleSolution(TypedDict, total=False):
231    content: Required[str]
232    "Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations."
233    content_type: str | None
234    "MIME type of `content`. Defaults to `application/x-yaml`; pass `application/json` when submitting JSON."
235    files: list[SolutionUpgradeInputSolutionBundleSolutionFilesItem] | None
236    "Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via `path://` URIs. Each entry is persisted as a child file record."
237    lookup_key: Required[str]
238    "Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config."
content: Required[str]

Raw solution.yaml body (YAML or JSON). Describes the solution structure, template references, and asset declarations.

content_type: str | None

MIME type of content. Defaults to application/x-yaml; pass application/json when submitting JSON.

Component files (READMEs, diagrams, fixtures) referenced by the solution.yaml via path:// URIs. Each entry is persisted as a child file record.

lookup_key: Required[str]

Stable lookup key for this solution. A suffix is appended at install time to namespace the stored config.

class SolutionUpgradeInputSolutionBundleTemplate(typing.TypedDict):
241class SolutionUpgradeInputSolutionBundleTemplate(TypedDict, total=False):
242    content: Required[str]
243    "Full text content of the agent template file, typically a YAML document."
244    content_type: str | None
245    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
246    relative_path: Required[str]
247    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
content: Required[str]

Full text content of the agent template file, typically a YAML document.

content_type: str | None

MIME type of the template content. Defaults to application/x-yaml when omitted.

relative_path: Required[str]

Bundle-relative path to the template file, used to derive its storage identity (e.g. "agent.yaml").

class SolutionUpgradeInputSolutionBundleTemplatesItem(typing.TypedDict):
250class SolutionUpgradeInputSolutionBundleTemplatesItem(TypedDict, total=False):
251    content: Required[str]
252    "Full text content of the agent template file, typically a YAML document."
253    content_type: str | None
254    "MIME type of the template content. Defaults to `application/x-yaml` when omitted."
255    relative_path: Required[str]
256    'Bundle-relative path to the template file, used to derive its storage identity (e.g. `"agent.yaml"`).'
content: Required[str]

Full text content of the agent template file, typically a YAML document.

content_type: str | None

MIME type of the template content. Defaults to application/x-yaml when omitted.

relative_path: Required[str]

Bundle-relative path to the template file, used to derive its storage identity (e.g. "agent.yaml").

class SolutionUpgradeInputSolutionBundle(typing.TypedDict):
259class SolutionUpgradeInputSolutionBundle(TypedDict, total=False):
260    configs: list[SolutionUpgradeInputSolutionBundleConfigsItem] | None
261    "Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install."
262    lookup_key_prefix: str | None
263    "String prepended (with a `-` separator) to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Typical value is `solutions-<install-id>`."
264    lookup_key_suffix: str | None
265    "String appended to every uploaded config's `lookup_key` and every `path://` reference in the solution body. Should be stable for a given install and unique per attempt."
266    setup_actions: list[SolutionUpgradeInputSolutionBundleSetupActionsItem] | None
267    "Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own `setup_actions`. Omit when bundling multiple templates."
268    skills: list[SolutionUpgradeInputSolutionBundleSkillsItem] | None
269    "Skill bundles (root config plus supporting files) that this solution depends on."
270    solution: Required[SolutionUpgradeInputSolutionBundleSolution]
271    "The solution config to install, including the solution.yaml body and any referenced component files."
272    template: SolutionUpgradeInputSolutionBundleTemplate | None
273    "Convenience shorthand for supplying a single template. Equivalent to setting `templates: [template]`. Mutually exclusive with `templates`. Use `templates` directly when bundling multiple sibling templates."
274    templates: list[SolutionUpgradeInputSolutionBundleTemplatesItem] | None
275    "Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via `template_path:`. Mutually exclusive with `template`."

Additional configs of any kind that the solution.yaml references and that should be upserted as part of this install.

lookup_key_prefix: str | None

String prepended (with a - separator) to every uploaded config's lookup_key and every path:// reference in the solution body. Typical value is solutions-<install-id>.

lookup_key_suffix: str | None

String appended to every uploaded config's lookup_key and every path:// reference in the solution body. Should be stable for a given install and unique per attempt.

Post-install setup checklist items for the wrapped template. Allowed only when the bundle contains a single template and that template's body does not already declare its own setup_actions. Omit when bundling multiple templates.

Skill bundles (root config plus supporting files) that this solution depends on.

The solution config to install, including the solution.yaml body and any referenced component files.

Convenience shorthand for supplying a single template. Equivalent to setting templates: [template]. Mutually exclusive with templates. Use templates directly when bundling multiple sibling templates.

Ordered list of templates the solution wraps. The first entry is the deployable template; additional entries are sibling templates it references via template_path:. Mutually exclusive with template.

class SolutionUpgradeInput(typing.TypedDict):
278class SolutionUpgradeInput(TypedDict, total=False):
279    "Upgrade an installed Solution"
280
281    allow_downgrade: bool | None
282    "When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`."
283    dry_run: bool | None
284    "When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`."
285    expected_review_fingerprint: str | None
286    "Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply."
287    org: str | None
288    "Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this."
289    solution_bundle: SolutionUpgradeInputSolutionBundle | None
290    "Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`."
291    target_solution: str | None
292    "Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`."

Upgrade an installed Solution

allow_downgrade: bool | None

When true, permits an incoming solution_version lower than the currently installed version. Defaults to false.

dry_run: bool | None

When true, computes and returns the full upgrade diff without persisting any changes. Defaults to false.

expected_review_fingerprint: str | None

Optional stale-review guard. Pass the review_fingerprint returned by a prior dry_run call to ensure the bundle has not changed between review and apply.

org: str | None

Organization ID (org_...) used to resolve org-scoped lookup_key values. Config IDs (cfg_...) are globally unique and do not require this.

solution_bundle: SolutionUpgradeInputSolutionBundle | None

Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with target_solution.

target_solution: str | None

Config ID (cfg_...) or lookup_key of the Solution to use as the incoming upgrade source. Mutually exclusive with solution_bundle.

class AsyncSolutionResource:
295class AsyncSolutionResource:
296    def __init__(self, http: HttpClient):
297        self._http = http
298
299    async def list(
300        self,
301        *,
302        page: int | None = None,
303        page_size: int | None = None,
304        lookup_key: str | None = None,
305        path_prefix: str | None = None,
306        owners: builtins.list[str] | None = None,
307    ) -> SolutionListResponse:
308        """
309        List Solutions
310        Returns a paginated list of Solutions visible to the caller, merging two
311        scopes: app-level Solutions (system-owned rows with no org affiliation,
312        visible to everyone including unauthenticated callers so they can power
313        the public catalog) and org-level Solutions (system-owned rows stamped with
314        the viewer's org ID, included when an authenticated viewer carries an org
315        context). Unauthenticated callers resolve to an app-scoped anonymous viewer
316        and therefore only ever see the app-level scope.
317        Solutions that appear under both scopes are deduplicated by their stable
318        `solution_id` value. The merged entry's `owners` array lists every scope the
319        Solution was found under (`"system"` and/or `"org"`). When the app-level copy
320        has a higher `solution_version` than the org-level copy, the response includes
321        `upgrade_available: true` and `latest_version` so callers can prompt for an
322        upgrade.
323
324        Args:
325            page: Page number to return. Defaults to `1`.
326            page_size: Number of Solutions per page. Defaults to `25`.
327            lookup_key: Filter to the Solution whose `lookup_key` matches exactly.
328            path_prefix: Filter to Solutions whose `virtual_path` starts with this prefix.
329            owners: Restrict results to a subset of owner scopes. Accepted values: `"system"` (app-level Solutions) and `"org"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
330
331        Returns:
332            Paginated list of Solution summaries visible to the caller.
333        """
334        query: dict[str, object] = {}
335        if page is not None:
336            query["page"] = page
337        if page_size is not None:
338            query["page_size"] = page_size
339        if lookup_key is not None:
340            query["lookup_key"] = lookup_key
341        if path_prefix is not None:
342            query["path_prefix"] = path_prefix
343        if owners is not None:
344            query["owners"] = owners
345        return await self._http.request(
346            "/api/v1/solutions",
347            query=query,
348            response_type=SolutionListResponse,
349        )
350
351    async def create(self, input: SolutionCreateInput) -> SolutionImportResponse:
352        """
353        Import a Solution into the library
354        Imports a Solution and its bundled configs (skills, scripts, templates, files)
355        into the library for the target scope. Two mutually exclusive import modes
356        are supported: pass `solution` to re-import an existing system-owned catalog
357        Solution by ID or `lookup_key`, or pass `solution_bundle` to supply a
358        self-contained inline bundle. Exactly one must be present.
359        The operation upserts the bundle in a single transaction. When `dry_run` is
360        `true` the same pipeline runs but the transaction is rolled back no rows are
361        persisted and the response reflects what would have been written. The
362        response shape is the same in both cases: the Solution summary plus
363        `installed_configs` listing each config the import created or would create.
364        Pairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the
365        Solution into the library; install provisions a runtime resource (Agent,
366        AgentRoutine, AgentTool, etc.) from an already-imported Solution.
367
368        Args:
369            input: Request body.
370            input.dry_run: When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`.
371            input.org: Organization ID (`org_...`) for the import destination scope.
372            input.solution: Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`.
373            input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`.
374            input.team: Team ID (`team_...`) for the import destination scope.
375            input.user: User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set.
376            input.virtual_path_prefix: Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix.
377
378        Returns:
379            The imported Solution in summary form, plus `installed_configs` one entry per config the transaction created or would create in `dry_run` mode. `installed_configs` is deprecated; prefer the `solution` summary shape for new integrations.
380        """
381        return await self._http.request(
382            "/api/v1/solutions",
383            method="POST",
384            body=input,
385            response_type=SolutionImportResponse,
386        )
387
388    async def delete(self, solution: str) -> None:
389        """
390        Delete a Solution
391        Permanently deletes an imported Solution and all configs bundled with it,
392        including templates, skills, scripts, and files. The deletion runs in a
393        single transaction; provider-stored blobs are swept asynchronously after commit.
394        Org-scope callers (for example, an org admin in the Library settings page) can
395        only delete their org's copy of the Solution. App-scope callers can delete
396        Solutions at either scope. RBAC is enforced inside the core delete flow.
397        Returns `204 No Content` on success.
398
399        Args:
400            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to delete.
401
402        Returns:
403            Empty body. HTTP 204 indicates the Solution was deleted successfully.
404        """
405        await self._http.request(f"/api/v1/solutions/{solution}", method="DELETE")
406
407    async def get(self, solution: str) -> SolutionSummary:
408        """
409        Retrieve a Solution
410        Returns a single Solution identified by its config ID (`cfg_...`) or
411        `lookup_key`, in the same summary shape the list endpoint emits. The response
412        always includes a freshly-minted `readme_url` call this endpoint to refresh
413        an expired README token without making any other state change.
414        Visibility matches the list endpoint: app-level Solutions (no org affiliation)
415        are visible to everyone including unauthenticated callers, so the public
416        catalog can render a Solution's detail page logged-out; org-scoped Solutions
417        are only visible to authenticated viewers whose org context matches. Anything
418        else returns 404.
419        When the resolved Solution is org-scoped, the endpoint compares its
420        `solution_version` against the matching app-level copy. If the app-level copy
421        is at a higher version the response includes `upgrade_available: true` and
422        `latest_version`. App-level resolutions always report `upgrade_available: false`.
423
424        Args:
425            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to retrieve.
426
427        Returns:
428            Solution summary including a freshly-minted `readme_url` token valid for one hour.
429        """
430        return await self._http.request(
431            f"/api/v1/solutions/{solution}",
432            response_type=SolutionSummary,
433        )
434
435    async def dependents(self, solution: str) -> SolutionDependentsResponse:
436        """
437        Preview Solution delete impact
438        Returns a read-only preview of what deleting the specified Solution would
439        affect: the agents that reference the Solution's bundle, and the count of
440        bundled configs that would be orphaned rather than cascade-deleted.
441        Use this endpoint before calling `DELETE /api/v1/solutions/:solution` to
442        surface a warning when live agents depend on the Solution.
443        Visibility scope mirrors the delete endpoint: org-scope viewers see their
444        org's copy; app-scope viewers can inspect either scope.
445
446        Args:
447            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to inspect.
448
449        Returns:
450            Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.
451        """
452        return await self._http.request(
453            f"/api/v1/solutions/{solution}/dependents",
454            response_type=SolutionDependentsResponse,
455        )
456
457    async def install(self, solution: str, input: SolutionInstallInput) -> SolutionInstallResponse:
458        """
459        Install a Solution
460        Provisions a runtime resource from an already-imported Solution. The type of
461        resource created depends on the template the Solution wraps: an
462        `AgentTemplate` produces an Agent, an `AutomationTemplate` produces an
463        Automation, and attachment templates (`AgentRoutineTemplate`,
464        `AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a
465        sub-resource to an existing Agent specified by `target`.
466        For Solutions that bundle more than one template, pass `template` (the ID or
467        `lookup_key` of the desired template) to select which one to provision.
468        Single-template Solutions do not require `template`.
469        Pairs with `POST /api/v1/solutions` (import): import puts the Solution into
470        the library; install provisions a runtime resource from it.
471
472        Args:
473            solution: Config ID (`cfg_...`) or `lookup_key` of the already-imported Solution to install from.
474            input: Request body.
475            input.allow_auto_import: When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing.
476            input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's `agent_key`).
477            input.lookup_key_suffix: Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
478            input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
479            input.org: Organization ID (`org_...`) for the install destination scope.
480            input.target: ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources.
481            input.team: Team ID (`team_...`) for the install destination scope.
482            input.template: Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
483            input.user: User ID (`usr_...`) for the install destination scope.
484
485        Returns:
486            The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.
487        """
488        return await self._http.request(
489            f"/api/v1/solutions/{solution}/install",
490            method="POST",
491            body=input,
492            response_type=SolutionInstallResponse,
493        )
494
495    async def readme(self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
496        """
497        Retrieve a Solution README or asset
498        Serves the README markdown or a bundled asset for an imported Solution. Both
499        modes use the same path and require a short-lived signed `token` in the query
500        string rather than an `Authorization` header, so browsers can load asset URLs
501        directly from `<img src>` attributes without custom request logic.
502        When `file` is omitted the response is the Solution's `readme` field rendered
503        as `text/markdown`. All local asset references in the markdown are rewritten to
504        point back at this endpoint with `?file=PATH&token=TOKEN` so browsers can load
505        images inline without additional authentication.
506        When `file` is set the response is the raw bytes of the matching asset (a File
507        child whose `relative_path` equals `PATH`, or an inline `assets` entry by
508        name) with the asset's stored `Content-Type`.
509        Tokens are scoped to a single Solution, carry the viewer's app, org, and
510        sandbox context from the time they were minted, and expire after one hour.
511        Obtain a fresh token by calling `GET /api/v1/solutions/:solution`, which
512        always returns a newly minted `readme_url`.
513
514        Args:
515            solution: Solution config ID (`cfg_...`) identifying the Solution whose README or asset to retrieve.
516            token: Signed URL token minted by the list or show endpoint. Expires after one hour.
517            file: Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown.
518
519        Returns:
520            README markdown (`text/markdown`) when `file` is omitted, or the raw asset bytes with the asset's `Content-Type` when `file` is set.
521        """
522        query: dict[str, object] = {}
523        query["token"] = token
524        if file is not None:
525            query["file"] = file
526        return await self._http.request_raw(f"/api/v1/solutions/{solution}/readme", query=query)
527
528    async def upgrade(self, solution: str, input: SolutionUpgradeInput) -> SolutionUpgradeResponse:
529        """
530        Upgrade an installed Solution
531        Applies an incoming bundle to an already-installed Solution in a single atomic
532        transaction, bringing its configs in line with the new bundle. Config IDs are
533        preserved across the upgrade. Configs that existed in the old bundle but are
534        absent from the new one are orphaned (top-level) or hard-deleted (child rows).
535        Two mutually exclusive source modes: pass `target_solution` to pull the
536        incoming bundle from an existing Solution by ID or `lookup_key`, or pass
537        `solution_bundle` to supply a complete inline bundle directly. Exactly one
538        must be present.
539        When `dry_run` is `true` the full diff is computed and returned but no
540        changes are written. Pass the dry-run response's `review_fingerprint` as
541        `expected_review_fingerprint` when applying to guard against the bundle
542        changing between review and apply.
543
544        Args:
545            solution: Config ID (`cfg_...`) or `lookup_key` of the currently installed Solution to upgrade.
546            input: Request body.
547            input.allow_downgrade: When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`.
548            input.dry_run: When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`.
549            input.expected_review_fingerprint: Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply.
550            input.org: Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this.
551            input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`.
552            input.target_solution: Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`.
553
554        Returns:
555            Updated Solution plus the full upgrade diff.
556        """
557        return await self._http.request(
558            f"/api/v1/solutions/{solution}/upgrade",
559            method="POST",
560            body=input,
561            response_type=SolutionUpgradeResponse,
562        )
AsyncSolutionResource(http: archastro.platform.runtime.http_client.HttpClient)
296    def __init__(self, http: HttpClient):
297        self._http = http
async def list( self, *, page: int | None = None, page_size: int | None = None, lookup_key: str | None = None, path_prefix: str | None = None, owners: list[str] | None = None) -> archastro.platform.types.common.SolutionListResponse:
299    async def list(
300        self,
301        *,
302        page: int | None = None,
303        page_size: int | None = None,
304        lookup_key: str | None = None,
305        path_prefix: str | None = None,
306        owners: builtins.list[str] | None = None,
307    ) -> SolutionListResponse:
308        """
309        List Solutions
310        Returns a paginated list of Solutions visible to the caller, merging two
311        scopes: app-level Solutions (system-owned rows with no org affiliation,
312        visible to everyone including unauthenticated callers so they can power
313        the public catalog) and org-level Solutions (system-owned rows stamped with
314        the viewer's org ID, included when an authenticated viewer carries an org
315        context). Unauthenticated callers resolve to an app-scoped anonymous viewer
316        and therefore only ever see the app-level scope.
317        Solutions that appear under both scopes are deduplicated by their stable
318        `solution_id` value. The merged entry's `owners` array lists every scope the
319        Solution was found under (`"system"` and/or `"org"`). When the app-level copy
320        has a higher `solution_version` than the org-level copy, the response includes
321        `upgrade_available: true` and `latest_version` so callers can prompt for an
322        upgrade.
323
324        Args:
325            page: Page number to return. Defaults to `1`.
326            page_size: Number of Solutions per page. Defaults to `25`.
327            lookup_key: Filter to the Solution whose `lookup_key` matches exactly.
328            path_prefix: Filter to Solutions whose `virtual_path` starts with this prefix.
329            owners: Restrict results to a subset of owner scopes. Accepted values: `"system"` (app-level Solutions) and `"org"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
330
331        Returns:
332            Paginated list of Solution summaries visible to the caller.
333        """
334        query: dict[str, object] = {}
335        if page is not None:
336            query["page"] = page
337        if page_size is not None:
338            query["page_size"] = page_size
339        if lookup_key is not None:
340            query["lookup_key"] = lookup_key
341        if path_prefix is not None:
342            query["path_prefix"] = path_prefix
343        if owners is not None:
344            query["owners"] = owners
345        return await self._http.request(
346            "/api/v1/solutions",
347            query=query,
348            response_type=SolutionListResponse,
349        )

List Solutions Returns a paginated list of Solutions visible to the caller, merging two scopes: app-level Solutions (system-owned rows with no org affiliation, visible to everyone including unauthenticated callers so they can power the public catalog) and org-level Solutions (system-owned rows stamped with the viewer's org ID, included when an authenticated viewer carries an org context). Unauthenticated callers resolve to an app-scoped anonymous viewer and therefore only ever see the app-level scope. Solutions that appear under both scopes are deduplicated by their stable solution_id value. The merged entry's owners array lists every scope the Solution was found under ("system" and/or "org"). When the app-level copy has a higher solution_version than the org-level copy, the response includes upgrade_available: true and latest_version so callers can prompt for an upgrade.

Arguments:
  • page: Page number to return. Defaults to 1.
  • page_size: Number of Solutions per page. Defaults to 25.
  • lookup_key: Filter to the Solution whose lookup_key matches exactly.
  • path_prefix: Filter to Solutions whose virtual_path starts with this prefix.
  • owners: Restrict results to a subset of owner scopes. Accepted values: "system" (app-level Solutions) and "org" (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
Returns:

Paginated list of Solution summaries visible to the caller.

async def create( self, input: SolutionCreateInput) -> archastro.platform.types.common.SolutionImportResponse:
351    async def create(self, input: SolutionCreateInput) -> SolutionImportResponse:
352        """
353        Import a Solution into the library
354        Imports a Solution and its bundled configs (skills, scripts, templates, files)
355        into the library for the target scope. Two mutually exclusive import modes
356        are supported: pass `solution` to re-import an existing system-owned catalog
357        Solution by ID or `lookup_key`, or pass `solution_bundle` to supply a
358        self-contained inline bundle. Exactly one must be present.
359        The operation upserts the bundle in a single transaction. When `dry_run` is
360        `true` the same pipeline runs but the transaction is rolled back no rows are
361        persisted and the response reflects what would have been written. The
362        response shape is the same in both cases: the Solution summary plus
363        `installed_configs` listing each config the import created or would create.
364        Pairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the
365        Solution into the library; install provisions a runtime resource (Agent,
366        AgentRoutine, AgentTool, etc.) from an already-imported Solution.
367
368        Args:
369            input: Request body.
370            input.dry_run: When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`.
371            input.org: Organization ID (`org_...`) for the import destination scope.
372            input.solution: Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`.
373            input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`.
374            input.team: Team ID (`team_...`) for the import destination scope.
375            input.user: User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set.
376            input.virtual_path_prefix: Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix.
377
378        Returns:
379            The imported Solution in summary form, plus `installed_configs` one entry per config the transaction created or would create in `dry_run` mode. `installed_configs` is deprecated; prefer the `solution` summary shape for new integrations.
380        """
381        return await self._http.request(
382            "/api/v1/solutions",
383            method="POST",
384            body=input,
385            response_type=SolutionImportResponse,
386        )

Import a Solution into the library Imports a Solution and its bundled configs (skills, scripts, templates, files) into the library for the target scope. Two mutually exclusive import modes are supported: pass solution to re-import an existing system-owned catalog Solution by ID or lookup_key, or pass solution_bundle to supply a self-contained inline bundle. Exactly one must be present. The operation upserts the bundle in a single transaction. When dry_run is true the same pipeline runs but the transaction is rolled back no rows are persisted and the response reflects what would have been written. The response shape is the same in both cases: the Solution summary plus installed_configs listing each config the import created or would create. Pairs with POST /api/v1/solutions/:solution/install: this endpoint puts the Solution into the library; install provisions a runtime resource (Agent, AgentRoutine, AgentTool, etc.) from an already-imported Solution.

Arguments:
  • input: Request body.
  • input.dry_run: When true, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to false.
  • input.org: Organization ID (org_...) for the import destination scope.
  • input.solution: Config ID (cfg_...) or lookup_key of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with solution_bundle.
  • input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with solution.
  • input.team: Team ID (team_...) for the import destination scope.
  • input.user: User ID (usr_...) for the import destination scope. Only one of org, team, or user may be set.
  • input.virtual_path_prefix: Path prefix under which all uploaded configs' virtual_path values are anchored (for example solutions/<uuid>). Stable per install; omit to use no prefix.
Returns:

The imported Solution in summary form, plus installed_configs one entry per config the transaction created or would create in dry_run mode. installed_configs is deprecated; prefer the solution summary shape for new integrations.

async def delete(self, solution: str) -> None:
388    async def delete(self, solution: str) -> None:
389        """
390        Delete a Solution
391        Permanently deletes an imported Solution and all configs bundled with it,
392        including templates, skills, scripts, and files. The deletion runs in a
393        single transaction; provider-stored blobs are swept asynchronously after commit.
394        Org-scope callers (for example, an org admin in the Library settings page) can
395        only delete their org's copy of the Solution. App-scope callers can delete
396        Solutions at either scope. RBAC is enforced inside the core delete flow.
397        Returns `204 No Content` on success.
398
399        Args:
400            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to delete.
401
402        Returns:
403            Empty body. HTTP 204 indicates the Solution was deleted successfully.
404        """
405        await self._http.request(f"/api/v1/solutions/{solution}", method="DELETE")

Delete a Solution Permanently deletes an imported Solution and all configs bundled with it, including templates, skills, scripts, and files. The deletion runs in a single transaction; provider-stored blobs are swept asynchronously after commit. Org-scope callers (for example, an org admin in the Library settings page) can only delete their org's copy of the Solution. App-scope callers can delete Solutions at either scope. RBAC is enforced inside the core delete flow. Returns 204 No Content on success.

Arguments:
  • solution: Solution config ID (cfg_...) or lookup_key of the Solution to delete.
Returns:

Empty body. HTTP 204 indicates the Solution was deleted successfully.

async def get(self, solution: str) -> archastro.platform.types.common.SolutionSummary:
407    async def get(self, solution: str) -> SolutionSummary:
408        """
409        Retrieve a Solution
410        Returns a single Solution identified by its config ID (`cfg_...`) or
411        `lookup_key`, in the same summary shape the list endpoint emits. The response
412        always includes a freshly-minted `readme_url` call this endpoint to refresh
413        an expired README token without making any other state change.
414        Visibility matches the list endpoint: app-level Solutions (no org affiliation)
415        are visible to everyone including unauthenticated callers, so the public
416        catalog can render a Solution's detail page logged-out; org-scoped Solutions
417        are only visible to authenticated viewers whose org context matches. Anything
418        else returns 404.
419        When the resolved Solution is org-scoped, the endpoint compares its
420        `solution_version` against the matching app-level copy. If the app-level copy
421        is at a higher version the response includes `upgrade_available: true` and
422        `latest_version`. App-level resolutions always report `upgrade_available: false`.
423
424        Args:
425            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to retrieve.
426
427        Returns:
428            Solution summary including a freshly-minted `readme_url` token valid for one hour.
429        """
430        return await self._http.request(
431            f"/api/v1/solutions/{solution}",
432            response_type=SolutionSummary,
433        )

Retrieve a Solution Returns a single Solution identified by its config ID (cfg_...) or lookup_key, in the same summary shape the list endpoint emits. The response always includes a freshly-minted readme_url call this endpoint to refresh an expired README token without making any other state change. Visibility matches the list endpoint: app-level Solutions (no org affiliation) are visible to everyone including unauthenticated callers, so the public catalog can render a Solution's detail page logged-out; org-scoped Solutions are only visible to authenticated viewers whose org context matches. Anything else returns 404. When the resolved Solution is org-scoped, the endpoint compares its solution_version against the matching app-level copy. If the app-level copy is at a higher version the response includes upgrade_available: true and latest_version. App-level resolutions always report upgrade_available: false.

Arguments:
  • solution: Solution config ID (cfg_...) or lookup_key of the Solution to retrieve.
Returns:

Solution summary including a freshly-minted readme_url token valid for one hour.

async def dependents( self, solution: str) -> archastro.platform.types.common.SolutionDependentsResponse:
435    async def dependents(self, solution: str) -> SolutionDependentsResponse:
436        """
437        Preview Solution delete impact
438        Returns a read-only preview of what deleting the specified Solution would
439        affect: the agents that reference the Solution's bundle, and the count of
440        bundled configs that would be orphaned rather than cascade-deleted.
441        Use this endpoint before calling `DELETE /api/v1/solutions/:solution` to
442        surface a warning when live agents depend on the Solution.
443        Visibility scope mirrors the delete endpoint: org-scope viewers see their
444        org's copy; app-scope viewers can inspect either scope.
445
446        Args:
447            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to inspect.
448
449        Returns:
450            Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.
451        """
452        return await self._http.request(
453            f"/api/v1/solutions/{solution}/dependents",
454            response_type=SolutionDependentsResponse,
455        )

Preview Solution delete impact Returns a read-only preview of what deleting the specified Solution would affect: the agents that reference the Solution's bundle, and the count of bundled configs that would be orphaned rather than cascade-deleted. Use this endpoint before calling DELETE /api/v1/solutions/:solution to surface a warning when live agents depend on the Solution. Visibility scope mirrors the delete endpoint: org-scope viewers see their org's copy; app-scope viewers can inspect either scope.

Arguments:
  • solution: Solution config ID (cfg_...) or lookup_key of the Solution to inspect.
Returns:

Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.

async def install( self, solution: str, input: SolutionInstallInput) -> archastro.platform.types.common.SolutionInstallResponse:
457    async def install(self, solution: str, input: SolutionInstallInput) -> SolutionInstallResponse:
458        """
459        Install a Solution
460        Provisions a runtime resource from an already-imported Solution. The type of
461        resource created depends on the template the Solution wraps: an
462        `AgentTemplate` produces an Agent, an `AutomationTemplate` produces an
463        Automation, and attachment templates (`AgentRoutineTemplate`,
464        `AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a
465        sub-resource to an existing Agent specified by `target`.
466        For Solutions that bundle more than one template, pass `template` (the ID or
467        `lookup_key` of the desired template) to select which one to provision.
468        Single-template Solutions do not require `template`.
469        Pairs with `POST /api/v1/solutions` (import): import puts the Solution into
470        the library; install provisions a runtime resource from it.
471
472        Args:
473            solution: Config ID (`cfg_...`) or `lookup_key` of the already-imported Solution to install from.
474            input: Request body.
475            input.allow_auto_import: When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing.
476            input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's `agent_key`).
477            input.lookup_key_suffix: Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
478            input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
479            input.org: Organization ID (`org_...`) for the install destination scope.
480            input.target: ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources.
481            input.team: Team ID (`team_...`) for the install destination scope.
482            input.template: Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
483            input.user: User ID (`usr_...`) for the install destination scope.
484
485        Returns:
486            The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.
487        """
488        return await self._http.request(
489            f"/api/v1/solutions/{solution}/install",
490            method="POST",
491            body=input,
492            response_type=SolutionInstallResponse,
493        )

Install a Solution Provisions a runtime resource from an already-imported Solution. The type of resource created depends on the template the Solution wraps: an AgentTemplate produces an Agent, an AutomationTemplate produces an Automation, and attachment templates (AgentRoutineTemplate, AgentToolTemplate, AgentSkillTemplate, AgentComputerTemplate) attach a sub-resource to an existing Agent specified by target. For Solutions that bundle more than one template, pass template (the ID or lookup_key of the desired template) to select which one to provision. Single-template Solutions do not require template. Pairs with POST /api/v1/solutions (import): import puts the Solution into the library; install provisions a runtime resource from it.

Arguments:
  • solution: Config ID (cfg_...) or lookup_key of the already-imported Solution to install from.
  • input: Request body.
  • input.allow_auto_import: When true, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit org param. Defaults to false; without it the endpoint returns 404 when the org-scoped Solution is missing.
  • input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's agent_key).
  • input.lookup_key_suffix: Suffix appended to every config_ref: resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
  • input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
  • input.org: Organization ID (org_...) for the install destination scope.
  • input.target: ID or lookup_key of the parent Agent to attach to. Required when installing an AgentRoutineTemplate, AgentToolTemplate, AgentSkillTemplate, or AgentComputerTemplate Solution, since those produce sub-resources attached to an existing Agent. Omit for AgentTemplate and AutomationTemplate Solutions, which provision standalone resources.
  • input.team: Team ID (team_...) for the install destination scope.
  • input.template: Config ID (cfg_...) or lookup_key of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
  • input.user: User ID (usr_...) for the install destination scope.
Returns:

The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.

async def readme( self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
495    async def readme(self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
496        """
497        Retrieve a Solution README or asset
498        Serves the README markdown or a bundled asset for an imported Solution. Both
499        modes use the same path and require a short-lived signed `token` in the query
500        string rather than an `Authorization` header, so browsers can load asset URLs
501        directly from `<img src>` attributes without custom request logic.
502        When `file` is omitted the response is the Solution's `readme` field rendered
503        as `text/markdown`. All local asset references in the markdown are rewritten to
504        point back at this endpoint with `?file=PATH&token=TOKEN` so browsers can load
505        images inline without additional authentication.
506        When `file` is set the response is the raw bytes of the matching asset (a File
507        child whose `relative_path` equals `PATH`, or an inline `assets` entry by
508        name) with the asset's stored `Content-Type`.
509        Tokens are scoped to a single Solution, carry the viewer's app, org, and
510        sandbox context from the time they were minted, and expire after one hour.
511        Obtain a fresh token by calling `GET /api/v1/solutions/:solution`, which
512        always returns a newly minted `readme_url`.
513
514        Args:
515            solution: Solution config ID (`cfg_...`) identifying the Solution whose README or asset to retrieve.
516            token: Signed URL token minted by the list or show endpoint. Expires after one hour.
517            file: Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown.
518
519        Returns:
520            README markdown (`text/markdown`) when `file` is omitted, or the raw asset bytes with the asset's `Content-Type` when `file` is set.
521        """
522        query: dict[str, object] = {}
523        query["token"] = token
524        if file is not None:
525            query["file"] = file
526        return await self._http.request_raw(f"/api/v1/solutions/{solution}/readme", query=query)

Retrieve a Solution README or asset Serves the README markdown or a bundled asset for an imported Solution. Both modes use the same path and require a short-lived signed token in the query string rather than an Authorization header, so browsers can load asset URLs directly from <img src> attributes without custom request logic. When file is omitted the response is the Solution's readme field rendered as text/markdown. All local asset references in the markdown are rewritten to point back at this endpoint with ?file=PATH&token=TOKEN so browsers can load images inline without additional authentication. When file is set the response is the raw bytes of the matching asset (a File child whose relative_path equals PATH, or an inline assets entry by name) with the asset's stored Content-Type. Tokens are scoped to a single Solution, carry the viewer's app, org, and sandbox context from the time they were minted, and expire after one hour. Obtain a fresh token by calling GET /api/v1/solutions/:solution, which always returns a newly minted readme_url.

Arguments:
  • solution: Solution config ID (cfg_...) identifying the Solution whose README or asset to retrieve.
  • token: Signed URL token minted by the list or show endpoint. Expires after one hour.
  • file: Relative path of the asset to retrieve (for example images/hero.png). When present the response is the raw asset bytes with its real Content-Type; when absent the response is the README markdown.
Returns:

README markdown (text/markdown) when file is omitted, or the raw asset bytes with the asset's Content-Type when file is set.

async def upgrade( self, solution: str, input: SolutionUpgradeInput) -> archastro.platform.types.common.SolutionUpgradeResponse:
528    async def upgrade(self, solution: str, input: SolutionUpgradeInput) -> SolutionUpgradeResponse:
529        """
530        Upgrade an installed Solution
531        Applies an incoming bundle to an already-installed Solution in a single atomic
532        transaction, bringing its configs in line with the new bundle. Config IDs are
533        preserved across the upgrade. Configs that existed in the old bundle but are
534        absent from the new one are orphaned (top-level) or hard-deleted (child rows).
535        Two mutually exclusive source modes: pass `target_solution` to pull the
536        incoming bundle from an existing Solution by ID or `lookup_key`, or pass
537        `solution_bundle` to supply a complete inline bundle directly. Exactly one
538        must be present.
539        When `dry_run` is `true` the full diff is computed and returned but no
540        changes are written. Pass the dry-run response's `review_fingerprint` as
541        `expected_review_fingerprint` when applying to guard against the bundle
542        changing between review and apply.
543
544        Args:
545            solution: Config ID (`cfg_...`) or `lookup_key` of the currently installed Solution to upgrade.
546            input: Request body.
547            input.allow_downgrade: When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`.
548            input.dry_run: When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`.
549            input.expected_review_fingerprint: Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply.
550            input.org: Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this.
551            input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`.
552            input.target_solution: Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`.
553
554        Returns:
555            Updated Solution plus the full upgrade diff.
556        """
557        return await self._http.request(
558            f"/api/v1/solutions/{solution}/upgrade",
559            method="POST",
560            body=input,
561            response_type=SolutionUpgradeResponse,
562        )

Upgrade an installed Solution Applies an incoming bundle to an already-installed Solution in a single atomic transaction, bringing its configs in line with the new bundle. Config IDs are preserved across the upgrade. Configs that existed in the old bundle but are absent from the new one are orphaned (top-level) or hard-deleted (child rows). Two mutually exclusive source modes: pass target_solution to pull the incoming bundle from an existing Solution by ID or lookup_key, or pass solution_bundle to supply a complete inline bundle directly. Exactly one must be present. When dry_run is true the full diff is computed and returned but no changes are written. Pass the dry-run response's review_fingerprint as expected_review_fingerprint when applying to guard against the bundle changing between review and apply.

Arguments:
  • solution: Config ID (cfg_...) or lookup_key of the currently installed Solution to upgrade.
  • input: Request body.
  • input.allow_downgrade: When true, permits an incoming solution_version lower than the currently installed version. Defaults to false.
  • input.dry_run: When true, computes and returns the full upgrade diff without persisting any changes. Defaults to false.
  • input.expected_review_fingerprint: Optional stale-review guard. Pass the review_fingerprint returned by a prior dry_run call to ensure the bundle has not changed between review and apply.
  • input.org: Organization ID (org_...) used to resolve org-scoped lookup_key values. Config IDs (cfg_...) are globally unique and do not require this.
  • input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with target_solution.
  • input.target_solution: Config ID (cfg_...) or lookup_key of the Solution to use as the incoming upgrade source. Mutually exclusive with solution_bundle.
Returns:

Updated Solution plus the full upgrade diff.

class SolutionResource:
565class SolutionResource:
566    def __init__(self, http: SyncHttpClient):
567        self._http = http
568
569    def list(
570        self,
571        *,
572        page: int | None = None,
573        page_size: int | None = None,
574        lookup_key: str | None = None,
575        path_prefix: str | None = None,
576        owners: builtins.list[str] | None = None,
577    ) -> SolutionListResponse:
578        """
579        List Solutions
580        Returns a paginated list of Solutions visible to the caller, merging two
581        scopes: app-level Solutions (system-owned rows with no org affiliation,
582        visible to everyone including unauthenticated callers so they can power
583        the public catalog) and org-level Solutions (system-owned rows stamped with
584        the viewer's org ID, included when an authenticated viewer carries an org
585        context). Unauthenticated callers resolve to an app-scoped anonymous viewer
586        and therefore only ever see the app-level scope.
587        Solutions that appear under both scopes are deduplicated by their stable
588        `solution_id` value. The merged entry's `owners` array lists every scope the
589        Solution was found under (`"system"` and/or `"org"`). When the app-level copy
590        has a higher `solution_version` than the org-level copy, the response includes
591        `upgrade_available: true` and `latest_version` so callers can prompt for an
592        upgrade.
593
594        Args:
595            page: Page number to return. Defaults to `1`.
596            page_size: Number of Solutions per page. Defaults to `25`.
597            lookup_key: Filter to the Solution whose `lookup_key` matches exactly.
598            path_prefix: Filter to Solutions whose `virtual_path` starts with this prefix.
599            owners: Restrict results to a subset of owner scopes. Accepted values: `"system"` (app-level Solutions) and `"org"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
600
601        Returns:
602            Paginated list of Solution summaries visible to the caller.
603        """
604        query: dict[str, object] = {}
605        if page is not None:
606            query["page"] = page
607        if page_size is not None:
608            query["page_size"] = page_size
609        if lookup_key is not None:
610            query["lookup_key"] = lookup_key
611        if path_prefix is not None:
612            query["path_prefix"] = path_prefix
613        if owners is not None:
614            query["owners"] = owners
615        return self._http.request(
616            "/api/v1/solutions",
617            query=query,
618            response_type=SolutionListResponse,
619        )
620
621    def create(self, input: SolutionCreateInput) -> SolutionImportResponse:
622        """
623        Import a Solution into the library
624        Imports a Solution and its bundled configs (skills, scripts, templates, files)
625        into the library for the target scope. Two mutually exclusive import modes
626        are supported: pass `solution` to re-import an existing system-owned catalog
627        Solution by ID or `lookup_key`, or pass `solution_bundle` to supply a
628        self-contained inline bundle. Exactly one must be present.
629        The operation upserts the bundle in a single transaction. When `dry_run` is
630        `true` the same pipeline runs but the transaction is rolled back no rows are
631        persisted and the response reflects what would have been written. The
632        response shape is the same in both cases: the Solution summary plus
633        `installed_configs` listing each config the import created or would create.
634        Pairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the
635        Solution into the library; install provisions a runtime resource (Agent,
636        AgentRoutine, AgentTool, etc.) from an already-imported Solution.
637
638        Args:
639            input: Request body.
640            input.dry_run: When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`.
641            input.org: Organization ID (`org_...`) for the import destination scope.
642            input.solution: Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`.
643            input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`.
644            input.team: Team ID (`team_...`) for the import destination scope.
645            input.user: User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set.
646            input.virtual_path_prefix: Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix.
647
648        Returns:
649            The imported Solution in summary form, plus `installed_configs` one entry per config the transaction created or would create in `dry_run` mode. `installed_configs` is deprecated; prefer the `solution` summary shape for new integrations.
650        """
651        return self._http.request(
652            "/api/v1/solutions",
653            method="POST",
654            body=input,
655            response_type=SolutionImportResponse,
656        )
657
658    def delete(self, solution: str) -> None:
659        """
660        Delete a Solution
661        Permanently deletes an imported Solution and all configs bundled with it,
662        including templates, skills, scripts, and files. The deletion runs in a
663        single transaction; provider-stored blobs are swept asynchronously after commit.
664        Org-scope callers (for example, an org admin in the Library settings page) can
665        only delete their org's copy of the Solution. App-scope callers can delete
666        Solutions at either scope. RBAC is enforced inside the core delete flow.
667        Returns `204 No Content` on success.
668
669        Args:
670            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to delete.
671
672        Returns:
673            Empty body. HTTP 204 indicates the Solution was deleted successfully.
674        """
675        self._http.request(f"/api/v1/solutions/{solution}", method="DELETE")
676
677    def get(self, solution: str) -> SolutionSummary:
678        """
679        Retrieve a Solution
680        Returns a single Solution identified by its config ID (`cfg_...`) or
681        `lookup_key`, in the same summary shape the list endpoint emits. The response
682        always includes a freshly-minted `readme_url` call this endpoint to refresh
683        an expired README token without making any other state change.
684        Visibility matches the list endpoint: app-level Solutions (no org affiliation)
685        are visible to everyone including unauthenticated callers, so the public
686        catalog can render a Solution's detail page logged-out; org-scoped Solutions
687        are only visible to authenticated viewers whose org context matches. Anything
688        else returns 404.
689        When the resolved Solution is org-scoped, the endpoint compares its
690        `solution_version` against the matching app-level copy. If the app-level copy
691        is at a higher version the response includes `upgrade_available: true` and
692        `latest_version`. App-level resolutions always report `upgrade_available: false`.
693
694        Args:
695            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to retrieve.
696
697        Returns:
698            Solution summary including a freshly-minted `readme_url` token valid for one hour.
699        """
700        return self._http.request(f"/api/v1/solutions/{solution}", response_type=SolutionSummary)
701
702    def dependents(self, solution: str) -> SolutionDependentsResponse:
703        """
704        Preview Solution delete impact
705        Returns a read-only preview of what deleting the specified Solution would
706        affect: the agents that reference the Solution's bundle, and the count of
707        bundled configs that would be orphaned rather than cascade-deleted.
708        Use this endpoint before calling `DELETE /api/v1/solutions/:solution` to
709        surface a warning when live agents depend on the Solution.
710        Visibility scope mirrors the delete endpoint: org-scope viewers see their
711        org's copy; app-scope viewers can inspect either scope.
712
713        Args:
714            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to inspect.
715
716        Returns:
717            Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.
718        """
719        return self._http.request(
720            f"/api/v1/solutions/{solution}/dependents",
721            response_type=SolutionDependentsResponse,
722        )
723
724    def install(self, solution: str, input: SolutionInstallInput) -> SolutionInstallResponse:
725        """
726        Install a Solution
727        Provisions a runtime resource from an already-imported Solution. The type of
728        resource created depends on the template the Solution wraps: an
729        `AgentTemplate` produces an Agent, an `AutomationTemplate` produces an
730        Automation, and attachment templates (`AgentRoutineTemplate`,
731        `AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a
732        sub-resource to an existing Agent specified by `target`.
733        For Solutions that bundle more than one template, pass `template` (the ID or
734        `lookup_key` of the desired template) to select which one to provision.
735        Single-template Solutions do not require `template`.
736        Pairs with `POST /api/v1/solutions` (import): import puts the Solution into
737        the library; install provisions a runtime resource from it.
738
739        Args:
740            solution: Config ID (`cfg_...`) or `lookup_key` of the already-imported Solution to install from.
741            input: Request body.
742            input.allow_auto_import: When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing.
743            input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's `agent_key`).
744            input.lookup_key_suffix: Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
745            input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
746            input.org: Organization ID (`org_...`) for the install destination scope.
747            input.target: ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources.
748            input.team: Team ID (`team_...`) for the install destination scope.
749            input.template: Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
750            input.user: User ID (`usr_...`) for the install destination scope.
751
752        Returns:
753            The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.
754        """
755        return self._http.request(
756            f"/api/v1/solutions/{solution}/install",
757            method="POST",
758            body=input,
759            response_type=SolutionInstallResponse,
760        )
761
762    def readme(self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
763        """
764        Retrieve a Solution README or asset
765        Serves the README markdown or a bundled asset for an imported Solution. Both
766        modes use the same path and require a short-lived signed `token` in the query
767        string rather than an `Authorization` header, so browsers can load asset URLs
768        directly from `<img src>` attributes without custom request logic.
769        When `file` is omitted the response is the Solution's `readme` field rendered
770        as `text/markdown`. All local asset references in the markdown are rewritten to
771        point back at this endpoint with `?file=PATH&token=TOKEN` so browsers can load
772        images inline without additional authentication.
773        When `file` is set the response is the raw bytes of the matching asset (a File
774        child whose `relative_path` equals `PATH`, or an inline `assets` entry by
775        name) with the asset's stored `Content-Type`.
776        Tokens are scoped to a single Solution, carry the viewer's app, org, and
777        sandbox context from the time they were minted, and expire after one hour.
778        Obtain a fresh token by calling `GET /api/v1/solutions/:solution`, which
779        always returns a newly minted `readme_url`.
780
781        Args:
782            solution: Solution config ID (`cfg_...`) identifying the Solution whose README or asset to retrieve.
783            token: Signed URL token minted by the list or show endpoint. Expires after one hour.
784            file: Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown.
785
786        Returns:
787            README markdown (`text/markdown`) when `file` is omitted, or the raw asset bytes with the asset's `Content-Type` when `file` is set.
788        """
789        query: dict[str, object] = {}
790        query["token"] = token
791        if file is not None:
792            query["file"] = file
793        return self._http.request_raw(f"/api/v1/solutions/{solution}/readme", query=query)
794
795    def upgrade(self, solution: str, input: SolutionUpgradeInput) -> SolutionUpgradeResponse:
796        """
797        Upgrade an installed Solution
798        Applies an incoming bundle to an already-installed Solution in a single atomic
799        transaction, bringing its configs in line with the new bundle. Config IDs are
800        preserved across the upgrade. Configs that existed in the old bundle but are
801        absent from the new one are orphaned (top-level) or hard-deleted (child rows).
802        Two mutually exclusive source modes: pass `target_solution` to pull the
803        incoming bundle from an existing Solution by ID or `lookup_key`, or pass
804        `solution_bundle` to supply a complete inline bundle directly. Exactly one
805        must be present.
806        When `dry_run` is `true` the full diff is computed and returned but no
807        changes are written. Pass the dry-run response's `review_fingerprint` as
808        `expected_review_fingerprint` when applying to guard against the bundle
809        changing between review and apply.
810
811        Args:
812            solution: Config ID (`cfg_...`) or `lookup_key` of the currently installed Solution to upgrade.
813            input: Request body.
814            input.allow_downgrade: When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`.
815            input.dry_run: When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`.
816            input.expected_review_fingerprint: Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply.
817            input.org: Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this.
818            input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`.
819            input.target_solution: Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`.
820
821        Returns:
822            Updated Solution plus the full upgrade diff.
823        """
824        return self._http.request(
825            f"/api/v1/solutions/{solution}/upgrade",
826            method="POST",
827            body=input,
828            response_type=SolutionUpgradeResponse,
829        )
SolutionResource(http: archastro.platform.runtime.http_client.SyncHttpClient)
566    def __init__(self, http: SyncHttpClient):
567        self._http = http
def list( self, *, page: int | None = None, page_size: int | None = None, lookup_key: str | None = None, path_prefix: str | None = None, owners: list[str] | None = None) -> archastro.platform.types.common.SolutionListResponse:
569    def list(
570        self,
571        *,
572        page: int | None = None,
573        page_size: int | None = None,
574        lookup_key: str | None = None,
575        path_prefix: str | None = None,
576        owners: builtins.list[str] | None = None,
577    ) -> SolutionListResponse:
578        """
579        List Solutions
580        Returns a paginated list of Solutions visible to the caller, merging two
581        scopes: app-level Solutions (system-owned rows with no org affiliation,
582        visible to everyone including unauthenticated callers so they can power
583        the public catalog) and org-level Solutions (system-owned rows stamped with
584        the viewer's org ID, included when an authenticated viewer carries an org
585        context). Unauthenticated callers resolve to an app-scoped anonymous viewer
586        and therefore only ever see the app-level scope.
587        Solutions that appear under both scopes are deduplicated by their stable
588        `solution_id` value. The merged entry's `owners` array lists every scope the
589        Solution was found under (`"system"` and/or `"org"`). When the app-level copy
590        has a higher `solution_version` than the org-level copy, the response includes
591        `upgrade_available: true` and `latest_version` so callers can prompt for an
592        upgrade.
593
594        Args:
595            page: Page number to return. Defaults to `1`.
596            page_size: Number of Solutions per page. Defaults to `25`.
597            lookup_key: Filter to the Solution whose `lookup_key` matches exactly.
598            path_prefix: Filter to Solutions whose `virtual_path` starts with this prefix.
599            owners: Restrict results to a subset of owner scopes. Accepted values: `"system"` (app-level Solutions) and `"org"` (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
600
601        Returns:
602            Paginated list of Solution summaries visible to the caller.
603        """
604        query: dict[str, object] = {}
605        if page is not None:
606            query["page"] = page
607        if page_size is not None:
608            query["page_size"] = page_size
609        if lookup_key is not None:
610            query["lookup_key"] = lookup_key
611        if path_prefix is not None:
612            query["path_prefix"] = path_prefix
613        if owners is not None:
614            query["owners"] = owners
615        return self._http.request(
616            "/api/v1/solutions",
617            query=query,
618            response_type=SolutionListResponse,
619        )

List Solutions Returns a paginated list of Solutions visible to the caller, merging two scopes: app-level Solutions (system-owned rows with no org affiliation, visible to everyone including unauthenticated callers so they can power the public catalog) and org-level Solutions (system-owned rows stamped with the viewer's org ID, included when an authenticated viewer carries an org context). Unauthenticated callers resolve to an app-scoped anonymous viewer and therefore only ever see the app-level scope. Solutions that appear under both scopes are deduplicated by their stable solution_id value. The merged entry's owners array lists every scope the Solution was found under ("system" and/or "org"). When the app-level copy has a higher solution_version than the org-level copy, the response includes upgrade_available: true and latest_version so callers can prompt for an upgrade.

Arguments:
  • page: Page number to return. Defaults to 1.
  • page_size: Number of Solutions per page. Defaults to 25.
  • lookup_key: Filter to the Solution whose lookup_key matches exactly.
  • path_prefix: Filter to Solutions whose virtual_path starts with this prefix.
  • owners: Restrict results to a subset of owner scopes. Accepted values: "system" (app-level Solutions) and "org" (viewer's org-level Solutions). Omit to include all scopes the viewer can see.
Returns:

Paginated list of Solution summaries visible to the caller.

621    def create(self, input: SolutionCreateInput) -> SolutionImportResponse:
622        """
623        Import a Solution into the library
624        Imports a Solution and its bundled configs (skills, scripts, templates, files)
625        into the library for the target scope. Two mutually exclusive import modes
626        are supported: pass `solution` to re-import an existing system-owned catalog
627        Solution by ID or `lookup_key`, or pass `solution_bundle` to supply a
628        self-contained inline bundle. Exactly one must be present.
629        The operation upserts the bundle in a single transaction. When `dry_run` is
630        `true` the same pipeline runs but the transaction is rolled back no rows are
631        persisted and the response reflects what would have been written. The
632        response shape is the same in both cases: the Solution summary plus
633        `installed_configs` listing each config the import created or would create.
634        Pairs with `POST /api/v1/solutions/:solution/install`: this endpoint puts the
635        Solution into the library; install provisions a runtime resource (Agent,
636        AgentRoutine, AgentTool, etc.) from an already-imported Solution.
637
638        Args:
639            input: Request body.
640            input.dry_run: When `true`, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to `false`.
641            input.org: Organization ID (`org_...`) for the import destination scope.
642            input.solution: Config ID (`cfg_...`) or `lookup_key` of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with `solution_bundle`.
643            input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with `solution`.
644            input.team: Team ID (`team_...`) for the import destination scope.
645            input.user: User ID (`usr_...`) for the import destination scope. Only one of `org`, `team`, or `user` may be set.
646            input.virtual_path_prefix: Path prefix under which all uploaded configs' `virtual_path` values are anchored (for example `solutions/<uuid>`). Stable per install; omit to use no prefix.
647
648        Returns:
649            The imported Solution in summary form, plus `installed_configs` one entry per config the transaction created or would create in `dry_run` mode. `installed_configs` is deprecated; prefer the `solution` summary shape for new integrations.
650        """
651        return self._http.request(
652            "/api/v1/solutions",
653            method="POST",
654            body=input,
655            response_type=SolutionImportResponse,
656        )

Import a Solution into the library Imports a Solution and its bundled configs (skills, scripts, templates, files) into the library for the target scope. Two mutually exclusive import modes are supported: pass solution to re-import an existing system-owned catalog Solution by ID or lookup_key, or pass solution_bundle to supply a self-contained inline bundle. Exactly one must be present. The operation upserts the bundle in a single transaction. When dry_run is true the same pipeline runs but the transaction is rolled back no rows are persisted and the response reflects what would have been written. The response shape is the same in both cases: the Solution summary plus installed_configs listing each config the import created or would create. Pairs with POST /api/v1/solutions/:solution/install: this endpoint puts the Solution into the library; install provisions a runtime resource (Agent, AgentRoutine, AgentTool, etc.) from an already-imported Solution.

Arguments:
  • input: Request body.
  • input.dry_run: When true, runs the full import pipeline but rolls back the transaction no rows are persisted. The response reflects what would have been written. Defaults to false.
  • input.org: Organization ID (org_...) for the import destination scope.
  • input.solution: Config ID (cfg_...) or lookup_key of an existing system-owned, org-less Solution to import into the target scope. Mutually exclusive with solution_bundle.
  • input.solution_bundle: Self-contained inline bundle containing the Solution metadata plus all bundled configs (skills, templates, configs, files). Mutually exclusive with solution.
  • input.team: Team ID (team_...) for the import destination scope.
  • input.user: User ID (usr_...) for the import destination scope. Only one of org, team, or user may be set.
  • input.virtual_path_prefix: Path prefix under which all uploaded configs' virtual_path values are anchored (for example solutions/<uuid>). Stable per install; omit to use no prefix.
Returns:

The imported Solution in summary form, plus installed_configs one entry per config the transaction created or would create in dry_run mode. installed_configs is deprecated; prefer the solution summary shape for new integrations.

def delete(self, solution: str) -> None:
658    def delete(self, solution: str) -> None:
659        """
660        Delete a Solution
661        Permanently deletes an imported Solution and all configs bundled with it,
662        including templates, skills, scripts, and files. The deletion runs in a
663        single transaction; provider-stored blobs are swept asynchronously after commit.
664        Org-scope callers (for example, an org admin in the Library settings page) can
665        only delete their org's copy of the Solution. App-scope callers can delete
666        Solutions at either scope. RBAC is enforced inside the core delete flow.
667        Returns `204 No Content` on success.
668
669        Args:
670            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to delete.
671
672        Returns:
673            Empty body. HTTP 204 indicates the Solution was deleted successfully.
674        """
675        self._http.request(f"/api/v1/solutions/{solution}", method="DELETE")

Delete a Solution Permanently deletes an imported Solution and all configs bundled with it, including templates, skills, scripts, and files. The deletion runs in a single transaction; provider-stored blobs are swept asynchronously after commit. Org-scope callers (for example, an org admin in the Library settings page) can only delete their org's copy of the Solution. App-scope callers can delete Solutions at either scope. RBAC is enforced inside the core delete flow. Returns 204 No Content on success.

Arguments:
  • solution: Solution config ID (cfg_...) or lookup_key of the Solution to delete.
Returns:

Empty body. HTTP 204 indicates the Solution was deleted successfully.

def get(self, solution: str) -> archastro.platform.types.common.SolutionSummary:
677    def get(self, solution: str) -> SolutionSummary:
678        """
679        Retrieve a Solution
680        Returns a single Solution identified by its config ID (`cfg_...`) or
681        `lookup_key`, in the same summary shape the list endpoint emits. The response
682        always includes a freshly-minted `readme_url` call this endpoint to refresh
683        an expired README token without making any other state change.
684        Visibility matches the list endpoint: app-level Solutions (no org affiliation)
685        are visible to everyone including unauthenticated callers, so the public
686        catalog can render a Solution's detail page logged-out; org-scoped Solutions
687        are only visible to authenticated viewers whose org context matches. Anything
688        else returns 404.
689        When the resolved Solution is org-scoped, the endpoint compares its
690        `solution_version` against the matching app-level copy. If the app-level copy
691        is at a higher version the response includes `upgrade_available: true` and
692        `latest_version`. App-level resolutions always report `upgrade_available: false`.
693
694        Args:
695            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to retrieve.
696
697        Returns:
698            Solution summary including a freshly-minted `readme_url` token valid for one hour.
699        """
700        return self._http.request(f"/api/v1/solutions/{solution}", response_type=SolutionSummary)

Retrieve a Solution Returns a single Solution identified by its config ID (cfg_...) or lookup_key, in the same summary shape the list endpoint emits. The response always includes a freshly-minted readme_url call this endpoint to refresh an expired README token without making any other state change. Visibility matches the list endpoint: app-level Solutions (no org affiliation) are visible to everyone including unauthenticated callers, so the public catalog can render a Solution's detail page logged-out; org-scoped Solutions are only visible to authenticated viewers whose org context matches. Anything else returns 404. When the resolved Solution is org-scoped, the endpoint compares its solution_version against the matching app-level copy. If the app-level copy is at a higher version the response includes upgrade_available: true and latest_version. App-level resolutions always report upgrade_available: false.

Arguments:
  • solution: Solution config ID (cfg_...) or lookup_key of the Solution to retrieve.
Returns:

Solution summary including a freshly-minted readme_url token valid for one hour.

def dependents( self, solution: str) -> archastro.platform.types.common.SolutionDependentsResponse:
702    def dependents(self, solution: str) -> SolutionDependentsResponse:
703        """
704        Preview Solution delete impact
705        Returns a read-only preview of what deleting the specified Solution would
706        affect: the agents that reference the Solution's bundle, and the count of
707        bundled configs that would be orphaned rather than cascade-deleted.
708        Use this endpoint before calling `DELETE /api/v1/solutions/:solution` to
709        surface a warning when live agents depend on the Solution.
710        Visibility scope mirrors the delete endpoint: org-scope viewers see their
711        org's copy; app-scope viewers can inspect either scope.
712
713        Args:
714            solution: Solution config ID (`cfg_...`) or `lookup_key` of the Solution to inspect.
715
716        Returns:
717            Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.
718        """
719        return self._http.request(
720            f"/api/v1/solutions/{solution}/dependents",
721            response_type=SolutionDependentsResponse,
722        )

Preview Solution delete impact Returns a read-only preview of what deleting the specified Solution would affect: the agents that reference the Solution's bundle, and the count of bundled configs that would be orphaned rather than cascade-deleted. Use this endpoint before calling DELETE /api/v1/solutions/:solution to surface a warning when live agents depend on the Solution. Visibility scope mirrors the delete endpoint: org-scope viewers see their org's copy; app-scope viewers can inspect either scope.

Arguments:
  • solution: Solution config ID (cfg_...) or lookup_key of the Solution to inspect.
Returns:

Agents that reference this Solution's bundle plus the count of configs that would be orphaned on delete.

def install( self, solution: str, input: SolutionInstallInput) -> archastro.platform.types.common.SolutionInstallResponse:
724    def install(self, solution: str, input: SolutionInstallInput) -> SolutionInstallResponse:
725        """
726        Install a Solution
727        Provisions a runtime resource from an already-imported Solution. The type of
728        resource created depends on the template the Solution wraps: an
729        `AgentTemplate` produces an Agent, an `AutomationTemplate` produces an
730        Automation, and attachment templates (`AgentRoutineTemplate`,
731        `AgentToolTemplate`, `AgentSkillTemplate`, `AgentComputerTemplate`) attach a
732        sub-resource to an existing Agent specified by `target`.
733        For Solutions that bundle more than one template, pass `template` (the ID or
734        `lookup_key` of the desired template) to select which one to provision.
735        Single-template Solutions do not require `template`.
736        Pairs with `POST /api/v1/solutions` (import): import puts the Solution into
737        the library; install provisions a runtime resource from it.
738
739        Args:
740            solution: Config ID (`cfg_...`) or `lookup_key` of the already-imported Solution to install from.
741            input: Request body.
742            input.allow_auto_import: When `true`, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit `org` param. Defaults to `false`; without it the endpoint returns 404 when the org-scoped Solution is missing.
743            input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's `agent_key`).
744            input.lookup_key_suffix: Suffix appended to every `config_ref:` resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
745            input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
746            input.org: Organization ID (`org_...`) for the install destination scope.
747            input.target: ID or `lookup_key` of the parent Agent to attach to. Required when installing an `AgentRoutineTemplate`, `AgentToolTemplate`, `AgentSkillTemplate`, or `AgentComputerTemplate` Solution, since those produce sub-resources attached to an existing Agent. Omit for `AgentTemplate` and `AutomationTemplate` Solutions, which provision standalone resources.
748            input.team: Team ID (`team_...`) for the install destination scope.
749            input.template: Config ID (`cfg_...`) or `lookup_key` of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
750            input.user: User ID (`usr_...`) for the install destination scope.
751
752        Returns:
753            The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.
754        """
755        return self._http.request(
756            f"/api/v1/solutions/{solution}/install",
757            method="POST",
758            body=input,
759            response_type=SolutionInstallResponse,
760        )

Install a Solution Provisions a runtime resource from an already-imported Solution. The type of resource created depends on the template the Solution wraps: an AgentTemplate produces an Agent, an AutomationTemplate produces an Automation, and attachment templates (AgentRoutineTemplate, AgentToolTemplate, AgentSkillTemplate, AgentComputerTemplate) attach a sub-resource to an existing Agent specified by target. For Solutions that bundle more than one template, pass template (the ID or lookup_key of the desired template) to select which one to provision. Single-template Solutions do not require template. Pairs with POST /api/v1/solutions (import): import puts the Solution into the library; install provisions a runtime resource from it.

Arguments:
  • solution: Config ID (cfg_...) or lookup_key of the already-imported Solution to install from.
  • input: Request body.
  • input.allow_auto_import: When true, automatically imports the Solution into the target tenant before installing if the org-scoped copy does not yet exist. Requires either an authenticated org user (member or admin) or a platform-privileged caller (S2S, developer JWT) that also supplies an explicit org param. Defaults to false; without it the endpoint returns 404 when the org-scoped Solution is missing.
  • input.lookup_key: Lookup key override for the provisioned resource (for example, the Agent's agent_key).
  • input.lookup_key_suffix: Suffix appended to every config_ref: resolution at install time. Should be stable per logical install and unique per attempt allows the same Solution to be installed multiple times in the same app without collisions.
  • input.name: Display name override for the provisioned Agent. Ignored for non-Agent Solutions.
  • input.org: Organization ID (org_...) for the install destination scope.
  • input.target: ID or lookup_key of the parent Agent to attach to. Required when installing an AgentRoutineTemplate, AgentToolTemplate, AgentSkillTemplate, or AgentComputerTemplate Solution, since those produce sub-resources attached to an existing Agent. Omit for AgentTemplate and AutomationTemplate Solutions, which provision standalone resources.
  • input.team: Team ID (team_...) for the install destination scope.
  • input.template: Config ID (cfg_...) or lookup_key of the template within the Solution to provision. Required when the Solution bundles more than one template; omit for single-template Solutions, where the only template is selected implicitly.
  • input.user: User ID (usr_...) for the install destination scope.
Returns:

The provisioned runtime resource (Agent, Automation, AgentRoutine, AgentTool, AgentSkill, or AgentComputer) together with the source Solution's config ID.

def readme( self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
762    def readme(self, solution: str, token: str, *, file: str | None = None) -> dict[str, str]:
763        """
764        Retrieve a Solution README or asset
765        Serves the README markdown or a bundled asset for an imported Solution. Both
766        modes use the same path and require a short-lived signed `token` in the query
767        string rather than an `Authorization` header, so browsers can load asset URLs
768        directly from `<img src>` attributes without custom request logic.
769        When `file` is omitted the response is the Solution's `readme` field rendered
770        as `text/markdown`. All local asset references in the markdown are rewritten to
771        point back at this endpoint with `?file=PATH&token=TOKEN` so browsers can load
772        images inline without additional authentication.
773        When `file` is set the response is the raw bytes of the matching asset (a File
774        child whose `relative_path` equals `PATH`, or an inline `assets` entry by
775        name) with the asset's stored `Content-Type`.
776        Tokens are scoped to a single Solution, carry the viewer's app, org, and
777        sandbox context from the time they were minted, and expire after one hour.
778        Obtain a fresh token by calling `GET /api/v1/solutions/:solution`, which
779        always returns a newly minted `readme_url`.
780
781        Args:
782            solution: Solution config ID (`cfg_...`) identifying the Solution whose README or asset to retrieve.
783            token: Signed URL token minted by the list or show endpoint. Expires after one hour.
784            file: Relative path of the asset to retrieve (for example `images/hero.png`). When present the response is the raw asset bytes with its real `Content-Type`; when absent the response is the README markdown.
785
786        Returns:
787            README markdown (`text/markdown`) when `file` is omitted, or the raw asset bytes with the asset's `Content-Type` when `file` is set.
788        """
789        query: dict[str, object] = {}
790        query["token"] = token
791        if file is not None:
792            query["file"] = file
793        return self._http.request_raw(f"/api/v1/solutions/{solution}/readme", query=query)

Retrieve a Solution README or asset Serves the README markdown or a bundled asset for an imported Solution. Both modes use the same path and require a short-lived signed token in the query string rather than an Authorization header, so browsers can load asset URLs directly from <img src> attributes without custom request logic. When file is omitted the response is the Solution's readme field rendered as text/markdown. All local asset references in the markdown are rewritten to point back at this endpoint with ?file=PATH&token=TOKEN so browsers can load images inline without additional authentication. When file is set the response is the raw bytes of the matching asset (a File child whose relative_path equals PATH, or an inline assets entry by name) with the asset's stored Content-Type. Tokens are scoped to a single Solution, carry the viewer's app, org, and sandbox context from the time they were minted, and expire after one hour. Obtain a fresh token by calling GET /api/v1/solutions/:solution, which always returns a newly minted readme_url.

Arguments:
  • solution: Solution config ID (cfg_...) identifying the Solution whose README or asset to retrieve.
  • token: Signed URL token minted by the list or show endpoint. Expires after one hour.
  • file: Relative path of the asset to retrieve (for example images/hero.png). When present the response is the raw asset bytes with its real Content-Type; when absent the response is the README markdown.
Returns:

README markdown (text/markdown) when file is omitted, or the raw asset bytes with the asset's Content-Type when file is set.

def upgrade( self, solution: str, input: SolutionUpgradeInput) -> archastro.platform.types.common.SolutionUpgradeResponse:
795    def upgrade(self, solution: str, input: SolutionUpgradeInput) -> SolutionUpgradeResponse:
796        """
797        Upgrade an installed Solution
798        Applies an incoming bundle to an already-installed Solution in a single atomic
799        transaction, bringing its configs in line with the new bundle. Config IDs are
800        preserved across the upgrade. Configs that existed in the old bundle but are
801        absent from the new one are orphaned (top-level) or hard-deleted (child rows).
802        Two mutually exclusive source modes: pass `target_solution` to pull the
803        incoming bundle from an existing Solution by ID or `lookup_key`, or pass
804        `solution_bundle` to supply a complete inline bundle directly. Exactly one
805        must be present.
806        When `dry_run` is `true` the full diff is computed and returned but no
807        changes are written. Pass the dry-run response's `review_fingerprint` as
808        `expected_review_fingerprint` when applying to guard against the bundle
809        changing between review and apply.
810
811        Args:
812            solution: Config ID (`cfg_...`) or `lookup_key` of the currently installed Solution to upgrade.
813            input: Request body.
814            input.allow_downgrade: When `true`, permits an incoming `solution_version` lower than the currently installed version. Defaults to `false`.
815            input.dry_run: When `true`, computes and returns the full upgrade diff without persisting any changes. Defaults to `false`.
816            input.expected_review_fingerprint: Optional stale-review guard. Pass the `review_fingerprint` returned by a prior `dry_run` call to ensure the bundle has not changed between review and apply.
817            input.org: Organization ID (`org_...`) used to resolve org-scoped `lookup_key` values. Config IDs (`cfg_...`) are globally unique and do not require this.
818            input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with `target_solution`.
819            input.target_solution: Config ID (`cfg_...`) or `lookup_key` of the Solution to use as the incoming upgrade source. Mutually exclusive with `solution_bundle`.
820
821        Returns:
822            Updated Solution plus the full upgrade diff.
823        """
824        return self._http.request(
825            f"/api/v1/solutions/{solution}/upgrade",
826            method="POST",
827            body=input,
828            response_type=SolutionUpgradeResponse,
829        )

Upgrade an installed Solution Applies an incoming bundle to an already-installed Solution in a single atomic transaction, bringing its configs in line with the new bundle. Config IDs are preserved across the upgrade. Configs that existed in the old bundle but are absent from the new one are orphaned (top-level) or hard-deleted (child rows). Two mutually exclusive source modes: pass target_solution to pull the incoming bundle from an existing Solution by ID or lookup_key, or pass solution_bundle to supply a complete inline bundle directly. Exactly one must be present. When dry_run is true the full diff is computed and returned but no changes are written. Pass the dry-run response's review_fingerprint as expected_review_fingerprint when applying to guard against the bundle changing between review and apply.

Arguments:
  • solution: Config ID (cfg_...) or lookup_key of the currently installed Solution to upgrade.
  • input: Request body.
  • input.allow_downgrade: When true, permits an incoming solution_version lower than the currently installed version. Defaults to false.
  • input.dry_run: When true, computes and returns the full upgrade diff without persisting any changes. Defaults to false.
  • input.expected_review_fingerprint: Optional stale-review guard. Pass the review_fingerprint returned by a prior dry_run call to ensure the bundle has not changed between review and apply.
  • input.org: Organization ID (org_...) used to resolve org-scoped lookup_key values. Config IDs (cfg_...) are globally unique and do not require this.
  • input.solution_bundle: Complete inline bundle for a direct upgrade, including Solution metadata, templates, skills, configs, files, and setup actions. Mutually exclusive with target_solution.
  • input.target_solution: Config ID (cfg_...) or lookup_key of the Solution to use as the incoming upgrade source. Mutually exclusive with solution_bundle.
Returns:

Updated Solution plus the full upgrade diff.