skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
objectstack-ai/objectstack215 installs

objectstack-ui

Author ObjectStack UI metadata — Views (list/form/kanban/calendar/gantt), Apps (navigation), Pages (structured plus the HTML and React source-authoring tiers, ADR-0080/0081), Dashboards, Reports, Charts, Actions, and package Docs (`src/docs/*.md`). Use when the user is adding `*.view.ts` / `*.page.ts` / `*.app.ts` / `*.dashboard.ts` / `*.report.ts` / `*.dataset.ts` / `*.action.ts` / `src/docs/*.md` files or designing a Studio-rendered UI surface. Do not use for: data schema (see objectstack-data), multi-step flows that BRANCH on logic between steps (those are `*.flow.ts` with `type: 'screen'` — see objectstack-automation; a stepped form over ONE object is this skill's `formViews` `type: 'wizard'`), or Studio's own admin UI (that ships with the platform). CEL expressions in visibility/conditional rules: load objectstack-formula alongside.

How do I install this agent skill?

npx skills add https://github.com/objectstack-ai/objectstack --skill objectstack-ui
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The objectstack-ui skill provides comprehensive instructions for designing user interfaces, navigation, and actions within the ObjectStack framework. The skill enables agents to author dynamic behavior through server-side scripts and React-based pages, which are core platform functionalities. While these features provide high-privilege access, they are intended for the development of managed applications and no malicious patterns, exfiltration, or obfuscation were identified.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

UI Design — ObjectStack UI Protocol

Expert instructions for designing user interfaces using the ObjectStack specification. This skill covers Views (list, form, kanban, calendar, …), App navigation, Dashboards, Reports, and Actions.


View Types

List Views

TypeWhen to Use
gridStandard data table — default for most objects
kanbanVisual board with columns (status-driven workflows)
galleryCard-based masonry layout (visual catalogues, contacts)
calendarDate-based scheduling (events, tasks, bookings)
timelineChronological activity stream
ganttProject management with dependency tracking
mapGeospatial records with location fields
chartAggregate visualisation over the object (mini chart view)
treeSelf-referencing hierarchy (tree-grid)

Form Views

TypeWhen to Use
simpleSingle-page form — suitable for objects with ≤ 15 fields
tabbedTabbed sections — for complex objects with many field groups
wizardStep-by-step flow — guided data entry (onboarding, applications)

Master-Detail Forms (parent + child line items)

To let users enter a record together with its child line items (invoice + lines, project + tasks) and save them atomically, you almost never need a custom page or form config. Prefer, in order:

  1. Relationship inlineEdit (default, zero UI config). Declare it in the DATA MODEL — set inlineEdit on the child's master_detail field that references the parent. Every standard New/Edit form for the parent (modal, drawer, full-page) then auto-renders the children and saves parent + children in one atomic /api/v1/batch. No view metadata needed. The true / 'grid' / 'form' ladder and what each value picks: objectstack-data → Relationships → Inline Editing.

  2. Form view subforms (override / tuning). Add to a form view only when you need to override the derived columns/order, or expose a child the relationship didn't mark inline:

    form: {
      type: 'simple',
      sections: [{ group: 'invoice_header' }],  // a declared fieldGroup
      subforms: [
        { childObject: 'invoice_line', // relationshipField + columns are
          title: 'Line Items',         // derived from the child object;
          addLabel: 'Add line' },      // set `columns` here only to override.
      ],
    },
    
  3. object-master-detail-form page block (bespoke layout). Use a page only for free-form layouts. Same details: [{ childObject }] shorthand.

The relationship FK and grid columns are derived from the child object's metadata in every case; select options and lookups carry through. A parent summary field rolls child values up server-side (see objectstack-data).

Line-item grid behaviors (grid mode). The editable grid is a real spreadsheet-style line editor (the QuickBooks / Stripe / NetSuite pattern), and every behaviour is derived from the DATA MODEL — computed columns, catalog typeahead auto-fill, persisted drag-reorder, and the live Subtotal → Tax → Total stack: objectstack-data → Relationships → Inline Editing. Three things are authored on this side: a trailing ghost row always exists, so never add an "Add line" button (typing in the ghost materialises a row; an untouched one is never persisted); autofill: false opts one column out of the typeahead copy; and the form's taxRateField overrides which parent field drives the totals.

Read side — detail-page related lists. The mirror of inlineEdit is the related list on the parent's record DETAIL page. You don't author it: every child relationship is shown as a related list by default (owned master_detail children first). Refine on the relationship:

  • relatedList: 'primary' — mark a CORE relationship; the detail page promotes it to its own tab (see layout below). A prominence intent, not a layout switch (ADR-0085).
  • relatedList: false — suppress a noisy child from the detail page.
  • relatedListTitle / relatedListColumns — override the derived title / columns (both optional; columns otherwise auto-derive from the child object's highlightFields). See objectstack-data → Relationships → Detail-page related lists.

Related-list layout. On the synthesized record detail page, each relatedList: 'primary' child gets its own tab; every other related list stacks under a single shared Related tab. Promoting a child table to a first-class tab is therefore a one-word change on the relationship — no custom page needed. The object still declares no per-surface layout hints: the old detail.relatedLayout toggle and object-level detail: {...} block stay removed (ADR-0085); relatedLayout: 'tabs' | 'stack' survives only as an app-level default override, not an object key. For arrangements the relationship layer can't express — filtered splits (e.g. Open vs Closed tabs), a chart/report tab, exact tab ordering — assign the object a custom record Page and lay it out explicitly with record:related_list (or inline-editable line_items) blocks.

Field Conditional Rules in Forms

Conditions that belong to a field's lifecycle — visibleWhen, readonlyWhen, requiredWhen — are declared on the DATA MODEL field, not in the form view; ObjectUI forms consume them. Their semantics and server behaviour: objectstack-data → Conditional Field Rules.

UI-side: inline master-detail grids evaluate these rules row-by-row against each child row. Use requiredWhen — the conditionalRequired alias was REMOVED in protocol 17 and is now a parse error. Load objectstack-formula when authoring non-trivial CEL.


Detailed Rules

  • List, Kanban & Gantt Views — defineView, data, columns, filtering, userFilters, toolbar search, sorting, kanban, gantt.
  • Navigation & Run Modes — App.create, the three run modes, record presentation.
  • Dashboards, Reports & Cubes — widgets, dataset binding, filters, compareTo, bucketing, options, drilldown, report config, cubes.
  • Pages & Docs — page types, regions, components, the html/react source tiers, styling, package docs.
  • Actions — locations, visibility, examples, ctx, new tab, params.

App Navigation

An App groups objects, dashboards, reports, and custom pages into a structured navigation tree. Build with App.create({...}) from @objectstack/spec/ui and register under defineStack({ apps: [...] }).

⛔ Exactly one App per type: 'app' package — defineStack refuses a second at load, per ADR-0019 (app-as-consumer-unit) D3. More audiences are requiredPermissions-gated groups inside that one app, never a second app.

Navigation Item Types

TypePropertiesPurpose
grouplabel, icon, expanded, children[]Collapsible group of items
objectobjectName, viewName?, recordId?, filters?, label, iconLink to an object list, a named view, a record deep-link, or a filters slice on the bare data surface
dashboarddashboardName, label, iconLink to a dashboard
reportreportName, label, iconLink to a report
pagepageName, label, iconLink to a custom Page
urlurl, label, iconExternal or custom URL
actionactionDef ({ actionName, params? }), label, iconRun an action instead of navigating
componentcomponentRef, params?, label, iconBuilt-in platform component; componentRef is a colon-joined registry key (metadata:resource)
docbook? / doc? (one required), label, iconPackage docs; inherits docs audience
separator—Visual separator

requiresObject / requiresService: Use these on any item that depends on an optional system object or kernel service so the nav item is automatically hidden when missing — never hard-code conditional UI.


Report Types

TypeWhen to Use
tabularFlat data table with columns and filters
summaryGrouped data with subtotals (e.g., revenue by region)
matrixCross-tab / pivot table (rows down × columns across)
joinedMulti-block analytic surface (combines several sub-reports)

There is no chart report type — a report visualizes via its embedded chart: config.


CRM UI Blueprint (Metadata-First)

Use this CRM-style structure as the canonical UI assembly reference:

UI SurfaceTypical LocationPattern to Follow
Multi-view object UIsrc/views/*.view.tsDefine default list + form, then named listViews / formViews for scenarios
Public formsrc/views/*.view.ts (formView with sharing: { enabled: true, allowAnonymous: true, publicLink: 'slug' })Web-to-Lead at GET/POST /api/v1/forms/:slug
App navigationsrc/apps/*.app.tsUse grouped nav trees, viewName shortcuts, and requiresObject for capability-aware visibility
Analytics datasetsrc/datasets/*.dataset.tsOne per object you want reportable — dashboards and reports bind a declared dataset by name, so an object without one has no analytics face
Dashboardssrc/dashboards/*.dashboard.tsCombine KPI + chart + table widgets with shared dateRange and globalFilters
Reportssrc/reports/*.report.tsSelect rows (dimensions) + values (measures) from that dataset; tabular/summary/matrix/joined
Record pagessrc/pages/*.page.tsCompose regions + components (page:header, record:highlights, related lists, tabs)
User actionssrc/actions/*.actions.tsUse flow for orchestration and modal for parameterized bulk mutations

This blueprint is the default for “build a complete metadata app UI” tasks.


Date Macros — Filter Placeholders

Filter values in list views, dashboards, reports and pages accept relative-date tokens ({today}, {current_month_start}, {30_days_ago}) and the two session tokens {current_user_id} / {current_org_id}. The vocabulary, both accepted spellings, the two resolvers and the near-miss list are owned by objectstack-query → rules/filters.md — load it before writing a filter token. An unrecognised token is a build error and a runtime throw, never a silent literal.

Two rules this package owns, because they are about UI surfaces rather than the token vocabulary:

  • A filter token is presentation scope, not security. It decides what a surface shows; RLS decides what a caller may read. Removing a {current_user_id} filter widens a view — it must never be the thing standing between a user and someone else's data.
  • AppContextSelector ids (e.g. {active_package}) resolve in navigation recordId / params only. Filters are not evaluated with the sidebar's selector state.

Actions

Actions are user-triggered operations attached to an object or a view. Register them under defineStack({ actions: [...] }).

Action Types

typePurposeRequired field
scriptRun an inline L2 hook body (sandboxed JS) on the serverbody (or target = registered function name)
urlNavigate to an internal route or external URLtarget
modalOpen a dialog (typically collecting params, then executing body)target
flowLaunch a screen/auto-launched flow by nametarget
apiCall a registered API endpointtarget
formOpen a FormView by name (routed to /_console/forms/:name)target

Common Pitfalls

  1. Putting too many columns in a grid view. Users rarely need more than 6–8 columns visible by default. Use hidden for secondary columns.

  2. Forgetting link: true on the primary column. The first meaningful column (usually the name/subject) should be the navigation link to the record detail.

  3. Putting widget grid placement in position. The grid-placement field is layout: { x, y, w, h } — position is not a widget key and the closed schema REJECTS it by name (it was silently dropped before protocol 17). layout is optional: omit it and the widget auto-flows (the Studio designer relies on this); set it only when you want an explicit grid position.


Verify your work

After authoring any *.view.ts / *.action.ts / *.dashboard.ts, run the author-time gate before reporting done:

os validate     # CEL predicates (record.<field>) + widget bindings + schema
# or: os build  # the same gates, plus emits dist/

Two UI-specific traps it catches, both silent at runtime otherwise:

  • Action / field predicate — a bare field ref in an action visible / disabled or a field visibleWhen (done instead of record.done) evaluates to null and hides the control on every record (the "button never shows" trap).
  • Dashboard widget binding — a widget dataset / dimensions / values that doesn't resolve to a declared dataset/field renders an empty chart (ADR-0021).

Don't report a view/action/dashboard done until os validate passes. In a scaffolded project the gate is npm run validate.


References

See references/_index.md for the full list of Zod schemas (with one-line descriptions) — pointers into node_modules/@objectstack/spec/src/. Always Read the source for exact field shapes; do not rely on memory of property names.

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/objectstack-ai/objectstack/objectstack-ui">View objectstack-ui on skillZs</a>