---
name: workspace-builder-30b9586ff149
description: Build ServiceNow App Engine Studio applications — sys_scope creation, scoped tables, sys_aw_workspace with lists/forms, the sys_ux_* record chain behind UI Builder workspaces, data brokers, and application export readiness checks. Never create a UI Builder page by inserting a sys_ux_page row.
license: Apache-2.0
compatibility: Designed for Serac and ServiceNow development
metadata:
  author: serac
  version: "1.0.0"
  category: servicenow
tools:
  - snow_query_table
  - snow_execute_script
  - snow_artifact_manage
  - snow_update_set_manage
  - snow_create_ux_experience
  - snow_create_ux_app_config
  - snow_create_ux_page_macroponent
  - snow_create_ux_page_registry
  - snow_create_ux_app_route
  - snow_update_ux_app_config_landing_page
  - snow_create_complete_workspace
  - snow_validate_workspace_configuration
  - snow_discover_all_workspaces
  - snow_uib_discover
  - snow_uib_page_manage (action='create', 'add_element', 'delete')
  - snow_create_uib_client_state
  - snow_create_uib_data_broker
  - snow_configure_uib_data_broker
---

# App Engine Studio & Workspace Builder for ServiceNow

App Engine Studio (AES) enables low-code application development with custom workspaces.

## AES Architecture

```
Application (sys_scope)
    ├── Tables & Forms
    ├── Workflows
    ├── Workspaces (sys_aw_workspace)
    │   ├── Lists
    │   ├── Forms
    │   └── Dashboards
    └── Portals
```

## Key Tables

| Table                  | Purpose                                                      |
| ---------------------- | ------------------------------------------------------------ |
| `sys_scope`            | Application scope                                             |
| `sys_app`              | Application record                                            |
| `sys_aw_workspace`     | Agent Workspace definition                                    |
| `sys_ux_experience`    | Next Experience workspace — top of the UI Builder chain       |
| `sys_ux_app_config`    | Workspace settings; links to the experience                   |
| `sys_ux_macroponent`   | Page content and custom components                            |
| `sys_ux_page_registry` | Registers a macroponent as a page of an app config            |
| `sys_ux_app_route`     | URL slug that reaches a registered page                       |
| `sys_ux_page`          | UI Builder page rows — read them, never insert one directly   |

## Application Development (ES5)

### Create Scoped Application

```javascript
// Create scoped application (ES5 ONLY!)
var app = new GlideRecord("sys_scope")
app.initialize()

// Basic info
app.setValue("name", "IT Asset Tracker")
app.setValue("scope", "x_myco_asset_track")
app.setValue("short_description", "Track IT assets across the organization")
app.setValue("version", "1.0.0")

// Vendor
app.setValue("vendor", "My Company")
app.setValue("vendor_prefix", "x_myco")

// License
app.setValue("licensable", true)

app.insert()
```

### Create Application Table

```javascript
// Create table in scoped app (ES5 ONLY!)
function createAppTable(scope, tableDef) {
  var table = new GlideRecord("sys_db_object")
  table.initialize()

  table.setValue("name", scope + "_" + tableDef.name)
  table.setValue("label", tableDef.label)
  table.setValue("super_class", tableDef.extends || "task")

  // Scope assignment
  table.setValue("sys_scope", getAppSysId(scope))

  // Options
  table.setValue("is_extendable", tableDef.extendable || false)
  table.setValue("create_access_controls", true)

  table.insert()

  // Create fields
  if (tableDef.fields) {
    for (var i = 0; i < tableDef.fields.length; i++) {
      createField(scope + "_" + tableDef.name, tableDef.fields[i])
    }
  }

  return table.getUniqueValue()
}

// Example
createAppTable("x_myco_asset_track", {
  name: "asset_item",
  label: "Asset Item",
  extends: "cmdb_ci",
  fields: [
    { name: "u_purchase_date", label: "Purchase Date", type: "glide_date" },
    { name: "u_warranty_end", label: "Warranty End", type: "glide_date" },
    { name: "u_assigned_user", label: "Assigned User", type: "reference", reference: "sys_user" },
  ],
})
```

## Workspace Configuration (ES5)

### Create Custom Workspace

```javascript
// Create workspace (ES5 ONLY!)
var workspace = new GlideRecord("sys_aw_workspace")
workspace.initialize()

workspace.setValue("name", "asset_tracker_workspace")
workspace.setValue("title", "Asset Tracker")
workspace.setValue("description", "Workspace for IT asset management")

// Primary table
workspace.setValue("primary_table", "x_myco_asset_track_asset_item")

// URL
workspace.setValue("url", "asset-tracker")

// Branding
workspace.setValue("icon", "laptop")
workspace.setValue("color", "#2E7D32")

// App scope
workspace.setValue("sys_scope", appScopeSysId)

// Features
workspace.setValue("agent_assist_enabled", false)
workspace.setValue("contextual_side_panel_enabled", true)

workspace.insert()
```

### Configure Workspace Lists

```javascript
// Create workspace list (ES5 ONLY!)
function createWorkspaceList(workspaceSysId, listDef) {
  var list = new GlideRecord("sys_aw_list")
  list.initialize()

  list.setValue("workspace", workspaceSysId)
  list.setValue("name", listDef.name)
  list.setValue("table", listDef.table)

  // Filter
  list.setValue("filter", listDef.filter || "")

  // Columns
  list.setValue("columns", listDef.columns.join(","))

  // Sorting
  if (listDef.orderBy) {
    list.setValue("order_by", listDef.orderBy)
    list.setValue("order_by_desc", listDef.orderDesc || false)
  }

  // Grouping
  if (listDef.groupBy) {
    list.setValue("group_by", listDef.groupBy)
  }

  list.insert()

  return list.getUniqueValue()
}

// Example lists
createWorkspaceList(workspaceSysId, {
  name: "My Assets",
  table: "x_myco_asset_track_asset_item",
  filter: "u_assigned_user=javascript:gs.getUserID()",
  columns: ["number", "name", "u_purchase_date", "u_warranty_end", "state"],
})

createWorkspaceList(workspaceSysId, {
  name: "Expiring Warranties",
  table: "x_myco_asset_track_asset_item",
  filter: "u_warranty_endBETWEENjavascript:gs.daysAgoStart(0)@javascript:gs.daysAgoEnd(-30)",
  columns: ["number", "name", "u_assigned_user", "u_warranty_end"],
  orderBy: "u_warranty_end",
})
```

## UI Builder Pages and Workspaces

The sections above write ordinary tables from a background script. This one does not work that way.

A Next Experience workspace is a graph of linked records, not a record. Inserting one row on its own —
`new GlideRecord("sys_ux_page")`, which is what earlier versions of this guide told you to do — succeeds,
returns a sys_id, and leaves you an orphan: no experience owns the page, no app config registers it, no route
reaches it. The row itself gives no hint that anything is missing. A lone `sys_ux_macroponent` insert is the
same story.

Two tools in this server will POST a `sys_ux_page` row through the Table API, and neither builds the rest of
the graph. `snow_artifact_manage (action='create', type='uib_page')` writes `name`, `title` and
`description` and stops. `snow_github_deploy` maps both `target_type: "uib_page"` and `"sys_ux_page"` onto
the same table, defaults `upsert` to `true`, and inserts a fresh row whenever its identifier matches nothing
— so a mistyped `target_identifier` produces this same orphan without saying so. Both report success. Use
`snow_artifact_manage` on UI Builder pages for `get`, `find`, `export` and `verify`, not `create`, and give
`snow_github_deploy` a `target_sys_id` or an identifier you have already read back off the instance.

The `sys_ux_page` tools in the `workspace` and `ui-builder` domains otherwise only read and delete. The one
exception is `snow_uib_page_manage (action='create')`, which does not touch the table at all — see *Where
scripting stops*.

### The record chain

| Step | Table                        | Tool                                       | Carries forward       |
| ---- | ---------------------------- | ------------------------------------------ | --------------------- |
| 1    | `sys_ux_experience`          | `snow_create_ux_experience`                | `experience_sys_id`   |
| 2    | `sys_ux_app_config`          | `snow_create_ux_app_config`                | `app_config_sys_id`   |
| 3    | `sys_ux_macroponent`         | `snow_create_ux_page_macroponent`          | `macroponent_sys_id`  |
| 4    | `sys_ux_page_registry`       | `snow_create_ux_page_registry`             | `sys_name`            |
| 5    | `sys_ux_app_route`           | `snow_create_ux_app_route`                 | `name`                |
| 6    | `sys_ux_app_config` (update) | `snow_update_ux_app_config_landing_page`   | —                     |

The order is enforced, not advisory. Step 2 refuses if step 1's experience cannot be read back. Step 4 GETs
both `sys_ux_app_config` and `sys_ux_macroponent` before it writes and refuses if either is missing. Step 5
joins back to step 4 through `page_sys_name` — per step 5's own schema that value is the registry's
`sys_name` **string**, not its sys_id. Step 6 is the one people skip: step 5's own response tells you to run
it, and until you do the app config has no `landing_page`.

Step 5 returns two keys that look interchangeable and are not. Its `name` input is the route name that
becomes the URL slug; its `route` is the path, which it defaults to `/<name>`. Step 6 wants the **name**:
`snow_update_ux_app_config_landing_page` takes `route_name` and PATCHes it straight into `landing_page`. Hand
it step 5's `route` and you set the landing page to `/home` where the route is called `home`.

Step 1 needs only a name. It derives `path` from that name (lowercased, spaces to hyphens) unless you pass
one, defaults `homepage` to `home`, and resolves the app shell itself by querying `sys_ux_macroponent` for
`name=uib_app_shell^category=app_shell`, falling back to
`name=x_snc_app_shell_uib_app_shell^category=app_shell`. If neither row is on the instance you get
`Could not find appShellUI macroponent (uib_app_shell) on this instance` before anything is written.

### The Builder Toolkit dependency

Step 1 is not a Table API write. It POSTs to `/api/sn_uibtk_api/buildertoolkit/experience`, a scoped
endpoint that appears in no reachable ServiceNow REST documentation — the scope name reads like UI
Builder's own toolkit, but treat that as a guess, not a contract, and expect nothing about it to survive a
family release. Steps 2 through 6 write through the ordinary `/api/now/table/...` API.

If the `sn_uibtk_api` scope is not on the instance, step 1 fails with
`Builder Toolkit API not available - UI Builder plugin may not be installed` and names the plugin
`com.snc.ui_builder_toolkit`. That is the tool working correctly, not a broken tool.

**The trap is step 2.** Before it writes anything, `snow_create_ux_app_config` GETs
`/api/sn_uibtk_api/buildertoolkit/experience` to confirm the experience exists, and swallows every failure
from that GET. On an instance without the toolkit the check 404s and the tool reports
`Experience '<sys_id>' not found or not accessible`. The sys_id in that message is fine; the toolkit is
missing. Check step 1's result and the plugin before you go re-copying sys_ids.

### Roles

`sn-roles.manifest.json` in the MCP package records an ACL probe of a live instance, and create permission
across the chain is not uniform:

| Table                  | Create needs one of                                                |
| ---------------------- | ------------------------------------------------------------------ |
| `sys_ux_app_config`    | `delegated_developer`, `ui_builder_admin`                          |
| `sys_ux_macroponent`   | `delegated_developer`, `ui_builder_admin`                          |
| `sys_ux_page_registry` | `canvas_admin`, `maint`, `ui_builder_admin`, `uxframework_designer` |
| `sys_ux_app_route`     | `ui_builder_admin`                                                 |
| `sys_ux_data_broker`   | `ui_builder_admin`                                                 |
| `sys_ux_page_element`  | `ui_builder_admin`, `uxframework_designer`                         |

So a `delegated_developer` clears steps 2 and 3 and then fails at step 4, with three records already
written. `ui_builder_admin` covers the whole chain; the manifest lists `admin` as sufficient everywhere.

When an ACL does reject a write, the failure is quieter than you expect. This server's HTTP client
re-throws ServiceNow error bodies as `ServiceNow: <message>` and drops the body's `detail` whenever
`message` is present — and `detail` is usually the half that says which table and which operation. If a
step fails and the message tells you nothing, query the table for the row rather than guessing.

### This server ships three different chains

They do not agree with each other. Know which one you called.

- **The six steps above.** Experience, app config, macroponent, page registry, route, landing page. No
  lists. Every record is one you can see and verify.
- **`snow_create_complete_workspace`.** Experience, app config, then a page created through the toolkit's
  `/page` endpoint, then — only if you pass `tables` — one `sys_ux_list_menu_config`, one
  `sys_ux_list_category` per table and one `sys_ux_list` per category. It never writes a
  `sys_ux_page_registry` or `sys_ux_app_route` row, because the toolkit `/page` call is what is supposed to
  produce the screen and route server-side. Whether it did is something you check, not something the tool
  reports.
- **`snow_create_workspace`** (the `ui-builder` domain, not `workspace`). Experience, app config, route,
  lists — and no page at all, so nothing lands on anything.

Prefer the six steps when the workspace has to be right, because you can inspect every row. Reach for
`snow_create_complete_workspace` when you were going to open UI Builder afterwards anyway. Do not build
something a user will open with `snow_create_workspace`.

None of the three read a URL back from the instance. `snow_create_ux_app_route` prints
`/now/experience<route>`, `snow_create_complete_workspace` prints `/now/<path>`, and `snow_create_workspace`
prints `<instance_url>/workspace/<path>` — all assembled inside the tool from strings you passed in. For a
path the instance actually knows, call `snow_discover_all_workspaces`, which reads the experience list back
from the toolkit — but read its output, not its status. When the toolkit call fails it does not fail the
tool: it pushes `{type: "UX Experience", error: "Builder Toolkit API not available"}` into the list and
returns success. On a toolkit-less instance that is a green result with no experiences in it.

One more route writer, and its name will mislead you. `snow_create_uib_page_registry`, in the `ui-builder`
domain, does not touch `sys_ux_page_registry` at all: it POSTs to `sys_ux_app_route` with a `page` column,
plus `roles`, `public` and `active`. That is a different shape from step 5, which links through `app_config`
and `page_sys_name`. Two tools, one table, two incompatible ideas of how a route finds its page — do not mix
them in one workspace, and do not reach for this one as step 4 because of what it is called.

### Where scripting stops

The chain leaves you five rows and an update that reference each other the way the tools intend. Whether
that adds up to a page UI Builder will open is not something this repo demonstrates and not something the
reachable documentation settles — verify it by opening the experience, not by reading a success payload.
What the chain definitely does not give you is a page with anything on it.

`snow_create_ux_page_macroponent` writes whatever object you pass as `composition` into that column as a
JSON string, and when you pass nothing it writes `{"layout":"single-column","components":[]}`. That default
is the tool's placeholder. Nothing in this repo establishes that it — or any composition you write by hand —
is a structure the UI Builder runtime renders, and this guide is not going to invent a format for you.

**Lay pages out in UI Builder.** Search the **All** menu for *UI Builder*, open the experience, open the
page. That is the supported editor for the component tree and it writes the composition the runtime expects.
Script the chain; author the page.

`snow_uib_page_manage (action='add_element')` looks like the way around that, and it is honest about what it
does: it POSTs `page`, `component`, `position` and a JSON `properties` string to `sys_ux_page_element`, a
real table with real ACLs. What is unproven is the connection. Its `page_id` is a `sys_ux_page` sys_id, and
the six-step chain never creates a `sys_ux_page` — so there is no demonstrated path from a chain-built page
to an element added this way. Do not build a layout on it without opening the result in UI Builder first.

`snow_uib_page_manage (action='create')` is the one candidate for supplying that missing `sys_ux_page`. It
takes an `experience_id` and a name and POSTs to the toolkit's `/page` endpoint — the same call
`snow_create_complete_workspace` makes — then returns the macroponent, screen and route ids the toolkit hands
back. So the server does the creating, which is why it can plausibly produce a real page and a route at once
where the Table API route cannot. Two caveats before you lean on it: it needs the toolkit, and the ids it
returns are the toolkit's, so confirm a `sys_ux_page` row actually exists before feeding one to
`add_element`. The verdict does not change — open it in UI Builder before you build on it.

The one macroponent internal this server edits through the toolkit rather than the Table API is client
state: `snow_create_uib_client_state` GETs `/api/sn_uibtk_api/buildertoolkit/macroponent`, appends to the
`state_properties` it finds there, and PATCHes the whole array back. It needs the macroponent sys_id. The
read-modify-write is unguarded — no version check, no optimistic lock — so two agents adding state to the
same page concurrently are the classic setup for a lost update. That outcome is read off the code, not
observed on an instance — add state from one caller at a time and you never have to find out.

### Verifying the chain

`snow_validate_workspace_configuration` with `workspace_type: "ux_experience"` does not check the parts that
break. It scores four things: the experience's `active` flag, whether any `sys_ux_app_config` has
`experience_assoc` pointing at it, whether that config has a `list_config_id`, and whether any
`sys_ux_page_property` rows reference it. It never reads `sys_ux_macroponent`, `sys_ux_page_registry` or
`sys_ux_app_route`, so a workspace with no page and no route can come back `passed`.

Check the last two yourself:

```javascript
// The page must be registered against the app config from step 2
await snow_query_table({
  table: "sys_ux_page_registry",
  query: "app_config=" + appConfigSysId,
  fields: ["sys_name", "macroponent", "active"],
})

// ...and a route must name that same sys_name
await snow_query_table({
  table: "sys_ux_app_route",
  query: "app_config=" + appConfigSysId,
  fields: ["name", "route", "page_sys_name", "active"],
})
```

Both should return a row, and the route's `page_sys_name` should equal the registry's `sys_name`.

Read that check with the same suspicion as the data-broker fields below. `sys_ux_page_registry.app_config`,
`sys_ux_page_registry.sys_name` and `sys_ux_app_route.page_sys_name` are the columns the step 4 and step 5
executors write; nothing in this repo confirms them against ServiceNow's own documentation, and the
`sys_ux_*` tables are not in the reachable docs. So an empty result has two readings — the row is missing,
or the column name is wrong — and `sysparm_query` will not tell you which, because an unrecognised field in
an encoded query does not raise an error. Before you trust an empty result, query the same table on
`sys_created_onONToday@javascript:gs.beginningOfToday()@javascript:gs.endOfToday()` with no `fields` list and
read the raw row the chain just wrote. If it is there under different column names, the chain worked and
this recipe is what is out of date.

Do not use `snow_uib_discover` as that check. Its `pages` action reads `sys_ux_page`, which the chain never
creates, and its `routes` action reads `sys_ux_page_registry` filtered by `experience=<sys_id>` — while the
chain links the registry through `app_config`, not `experience`. Neither one filters on anything your six
steps wrote, so whatever it returns says nothing about your workspace. Use it to look at pages that were
authored in UI Builder, and `snow_discover_all_workspaces` to enumerate experiences.

One `snow_query_table` quirk matters when you go looking at a macroponent: `truncate_output` defaults to
`true`, and it cuts to 200 characters with `... [truncated, N chars total]` appended. Which strings it cuts
depends on the field's name. If the name contains one of its large-content substrings — `script`,
`description`, `content`, `body`, `json`, `html`, `xml`, `template`, `comments` and about ten more —
anything past 200 characters is cut. Every other field gets to 400 first. `composition` is not on that list
so it survives to 400, and a real one is far longer than that; `short_description` matches on `description`
and so gets cut at 200. Pass `truncate_output: false` whenever you intend to compare values, or you will
compare two truncations and conclude they match.

### Data resources (data brokers)

Same boundary, same rule. Do not create data brokers from a background script on `sys_ux_data_broker`. The
field set earlier versions of this guide used there — `type: "script"` plus a `script` column — is not one
anything in this repo confirms.

Two tools write the table:

- `snow_create_uib_data_broker` POSTs `page`, `name`, `table`, `query` and `limit`, plus `fields`
  (comma-joined) and `order_by` when you pass them.
- `snow_configure_uib_data_broker` PATCHes an existing row with any of `query`, `refresh_interval`,
  `enable_caching`, `cache_duration`, `parameters` and `filters` — the last two JSON-stringified.

Those column names are this server's assumption about `sys_ux_data_broker`, not something the repo verifies
against a real broker. Do not treat a success response as proof the fields landed: read the row straight
back with `snow_query_table` and compare it against a broker created in UI Builder on the same instance. If
the shapes differ, author in UI Builder and use these tools only to read.

Broker script bodies and the GraphQL broker query shape belong to the `ui-builder-patterns` guide. They are
server-side and ES5, like everything else in this file.

Deletion is the one operation here that walks the graph: `snow_uib_page_manage (action='delete')` with
`delete_dependencies` left at its default first deletes the `sys_ux_page_element`, `sys_ux_data_broker`,
`sys_ux_client_script` and `sys_ux_app_route` rows whose `page` points at the page, then the page itself.
Passing `delete_dependencies: false` leaves all of them behind — more orphans, in the table you were trying
to clean up.

## Application Deployment (ES5)

### Create Update Set

```javascript
// Create update set for app deployment (ES5 ONLY!)
function createAppUpdateSet(appName, description) {
  var updateSet = new GlideRecord("sys_update_set")
  updateSet.initialize()
  updateSet.setValue("name", appName + " - " + new GlideDateTime().getDate())
  updateSet.setValue("description", description)
  updateSet.setValue("application", getAppSysId(appName))
  updateSet.setValue("state", "in progress")
  return updateSet.insert()
}
```

### Export Application

```javascript
// Prepare app for export (ES5 ONLY!)
function prepareAppExport(appScope) {
  // Validate all components
  var issues = []

  // Check for missing dependencies
  var dependency = new GlideRecord("sys_app_dependency")
  dependency.addQuery("app.scope", appScope)
  dependency.query()

  while (dependency.next()) {
    if (!isDependencyInstalled(dependency.getValue("dependency"))) {
      issues.push("Missing dependency: " + dependency.dependency.getDisplayValue())
    }
  }

  // Validate update sets
  var updateSet = new GlideRecord("sys_update_set")
  updateSet.addQuery("application.scope", appScope)
  updateSet.addQuery("state", "in progress")
  updateSet.query()

  while (updateSet.next()) {
    issues.push("Open update set: " + updateSet.getValue("name"))
  }

  return {
    ready: issues.length === 0,
    issues: issues,
  }
}
```

## MCP Tool Integration

The `tools:` list in this file's frontmatter is the full set. There is deliberately no second list here: a
summary table used to sit in this spot and it drifted out of date the moment the UI Builder chain was added,
which is a worse failure than having one list.

### Example Workflow

```javascript
// 1. Query applications
await snow_query_table({
  table: "sys_scope",
  query: "scopeSTARTSWITHx_",
  fields: "name,scope,version,vendor",
})

// 2. Find app tables
await snow_query_table({
  table: "sys_db_object",
  query: "nameSTARTSWITHx_myco",
  fields: "name,label,super_class",
})

// 3. Get workspace configs
await snow_query_table({
  table: "sys_aw_workspace",
  query: "sys_scope.scopeSTARTSWITHx_",
  fields: "name,title,primary_table,url",
})
```

## Best Practices

1. **Naming Conventions** - Consistent prefixes
2. **Scoped Apps** - Use scope isolation
3. **Reusable Components** - Modular design
4. **Data Brokers** - Efficient data fetching
5. **Workspace Design** - User-focused layouts
6. **Testing** - ATF tests for apps
7. **Documentation** - App documentation
8. **ES5 Only** - No modern JavaScript syntax


---
Source attribution: serac
Original project: https://github.com/groeimetai/snow-flow/blob/af3ad2b3c01305526a44b2647415ba794237462c/packages/skills/workspace-builder/SKILL.md
License: Apache-2.0
License information: https://www.apache.org/licenses/LICENSE-2.0
Original upstream instructions; downloaded from Mega AI Hub.

## Upstream license notice

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2026 Serac Labs

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.



# Mega AI Hub resource metadata

Creator / publisher: serac
Original project: https://github.com/groeimetai/snow-flow/blob/af3ad2b3c01305526a44b2647415ba794237462c/packages/skills/workspace-builder/SKILL.md
Attribution basis: Source repository record

Fields of work: Product Management, Development & Engineering, Sales
Roles: Product Manager, Backend Developer, Growth Product Manager, DevOps / SRE, Business Development
Specialties: Frontend, Design, Word Documents, Testing, DevOps
Tools: Snow_Query_Table, Snow_Execute_Script_With_Output, Snow_Find_Artifact, Snow_Update_Set_Create
Country applicability: Country not specified
Classification basis: Source category, role and specialization labels
Instruction SHA-256: 7a4cce85a89c48790fb8be714c6fdeb7b1f02fc94c2626d431a6f8013c3f49b3
