Tips for AI-FDE Skills.md?

Hey guys! :blush:

So I saw that AI FDE dropped the new “Skills” feature, but I’m honestly a bit lost on how to make the most of it.

For those who already have it up and running, I’d love to get your insights on a couple of things:

  • Your Current Setup: What Skills do you have active right now, and how have they been working out for you?

  • Top Recommendations: Are there any essential Skills I should definitely add? (Bonus points for beginner-friendly ones! :raising_hands:)

Would love to hear how you guys are using it. Thanks a ton!

Something around Huggingface - ML Intern and Karparthy - Autoresearch could be interesting:

GitHub - huggingface/ml-intern: :hugs: ml-intern: an open-source ML engineer that reads papers, trains models, and ships ML models · GitHub

GitHub - karpathy/autoresearch: AI agents running research on single-GPU nanochat training automatically · GitHub

With native handling of Model Asset, Model Studio & Modeling objectives

Hey @ztophoon ,

The only skill I’m utilising right now is a design skill for workshop I called workshop-application-design, it is based off:

https://www.palantir.com/docs/foundry/workshop/application-design-best-practices

https://www.palantir.com/docs/foundry/workshop/application-design-components/

It’s useful if you use AI FDE to create/update workshop applications or to make a quick demo as it makes the workshop more intuitive for users and creates better styling. You can also get AI FDE to create workshops for you with notional data and then try to recreate it yourself as a way to develop your workshop skills.

I’ll paste the skill below if you or anyone else wants to try it:

Name:

workshop-application-design

Description:

Activate whenever you create, lay out, edit, or review a Workshop module/application — i.e., any time you write or modify Workshop DSL (pages, layouts, sections, headers, module headers, filters, tables, overlays) or make decisions about visual hierarchy, spacing, padding, elevation, navigation placement, or where components should live. Apply before finalising any Workshop layout.

Markdown editor:

# Workshop application design

Design and layout guidance for building intuitive, unified Workshop modules, with the Workshop DSL patterns that implement each rule. Apply this before finalizing any page, section, or header.

## When to apply
Use this skill whenever you generate or edit Workshop DSL, or make layout decisions: page structure, `columns`/`rows`/`tabbed` layouts, sections, headers, module headers, filter/table placement, padding, elevation, navigation, and overlays.

## Enforce these limits
| Rule | Target |
| --- | --- |
| Primary actions in top‑level navigation | ≤ 5 |
| Visible components per view (buttons, panels, widgets) | ≤ 10 |
| Whitespace share of the screen | 30–40% |
| Elevated / shaded "important" area per page | exactly 1 |
| Touch targets when a section scrolls | ≥ 30px |
| Default padding | `compact` |

## Module skeleton
Every module is an arrow function that returns a default `page`. Give every widget and section an `editorLabel` (builder‑only, not shown to viewers). Never invent `id`s — only reuse ones that already exist.

```ts
(W: WorkshopBuilder) => {
  const hero = W.widget.headerText(
    { title: "Fleet Operations", subtitle: "Live status across all aircraft" },
    { editorLabel: "Hero header" },
  );

  return {
    page: W.layout.page(
      "Fleet Operations",
      W.layout.layoutDefinition.columns([
        { width: W.layout.size.flex(1), content: hero },
      ]),
    ),
  };
};
```

## 1. Match the layout to the F‑pattern
Support natural left‑to‑right, top‑to‑bottom eye tracking. Pick one:

- **Grid** — info flows horizontally (`columns`).
- **Column** — info flows vertically with navigation at the top of each panel (`rows`).
- **Row + column combo (recommended default)** — filters anchored on the **left**, KPI metric cards across the **top**, primary content filling the rest.

`content` accepts a `Widget` **or** a `Section`. Wrap widgets in sections so they get headers, padding, and elevation. Column `width` is `absolute` or `flex` only (never `auto`); row `height` can also be `auto`.

```ts
const page = W.layout.page(
  "Claims Dashboard",
  W.layout.layoutDefinition.columns(
    [
      { width: W.layout.size.absolute(300), content: filtersSection }, // filters pinned LEFT
      { width: W.layout.size.flex(1), content: contentSection },       // content flows RIGHT
    ],
    { layoutDisplay: W.layout.display.compact() },
  ),
);

const contentSection = W.layout.section(
  W.layout.layoutDefinition.rows(
    [
      { height: W.layout.size.auto(), content: kpiRow },       // metric cards on top
      { height: W.layout.size.flex(1), content: claimsTable }, // primary content fills remaining space
    ],
    { layoutDisplay: W.layout.display.compact() },
  ),
  W.layout.section.header({
    title: W.layout.staticOrVariable.static("Open Claims"),
    description: W.layout.staticOrVariable.static("Claims awaiting adjudication"),
    height: W.layout.section.headerHeight.auto,
    alignWithSectionPadding: true,
    leadingText: W.layout.staticOrVariable.static(""),
    bold: true,
    icon: "shield",
  }),
  { editorLabel: "Claims content", elevation: "ELEVATED", backgroundColor: "WHITE" },
);
```

> Put KPI summaries in a top row or left rail using `W.widget.metricCard(...)`. Keep the body of a section text‑light; `headerText` is for header/toolbar slots, and `markdown` is for body copy.

## 2. Write a clear header hierarchy
Three descriptive levels, largest to smallest. Keep action buttons in the header (`rightComponents` / `titleComponents`), not scattered in the body.

- `pageHeader` — the app/page purpose. Use once, at the top.
- `header` — groups content within the page (second level).
- `subheader` — context under a section header.
- `calloutHeader` — an accented banner for a single high‑emphasis area.

```ts
const pageHeader = W.layout.section.pageHeader({
  title: W.layout.staticOrVariable.static("Claims Operations"),
  description: W.layout.staticOrVariable.static("Review, triage, and adjudicate open claims"),
  height: W.layout.section.headerHeight.auto,
  alignWithSectionPadding: true,
  leadingText: W.layout.staticOrVariable.static(""),
  bold: true,
});

const sectionHeader = W.layout.section.header({
  title: W.layout.staticOrVariable.static("High-priority queue"),
  description: W.layout.staticOrVariable.static("SLA breaches in the next 24h"),
  height: W.layout.section.headerHeight.auto,
  alignWithSectionPadding: true,
  leadingText: W.layout.staticOrVariable.static(""),
  bold: true,
  rightComponents: [refreshButton], // actions belong in the header
});
```

## 3. Space and group with padding, containers, and dividers
Default to `compact`. When you need breathing room, the reliable custom recipe is ~80% card size with 16px spacing. Separate **distinct** groups with padding/containers (sections); separate **related** content within a section with dividers — do not rely on dividers to separate groups.

```ts
// Default
{ layoutDisplay: W.layout.display.compact() }

// Custom breathing room: 80% card size, 16px between, 16px around
{
  layoutDisplay: W.layout.display.custom(
    W.layout.cardSize.percent(80),
    16, // space BETWEEN cards
    16, // space AROUND the group
  ),
}

// Remove dividers when padding already separates content
{ layoutDisplay: W.layout.display.noPadding(true) } // true = hide dividers
```

## 4. Use borders and elevation to signal importance
`elevation` options: `"ELEVATED"` (drop shadow = important), `"INNERSHADOW"` (recessed = less important), `"BORDER"`, `"BORDERLESS"`. Lighter backgrounds signal importance; darker backgrounds signal secondary content (filters, collapsibles). **Apply the elevated/shaded treatment only once per page.**

```ts
// Primary action area — draws the eye
{ editorLabel: "Primary action", elevation: "ELEVATED", backgroundColor: "WHITE" }

// Secondary area (e.g. filters) — recede it
{ editorLabel: "Filters", elevation: "INNERSHADOW", backgroundColor: "LIGHT_GRAY4" }
```
`backgroundColor` accepts named `BaseLayoutColor` values (e.g. `"WHITE"`, `"LIGHT_GRAY4"`, `"DARK_GRAY3"`, `"TRANSPARENT"`) or a hex string like `"#1F4B99"`.

## 5. Unify the app: module header + navigation
Give multi‑page apps a persistent primary header: logo top‑left, global settings top‑right, and ≤ 5 primary destinations. Standardize placement across pages.

```ts
return {
  page: W.layout.page("Home", mainLayout),
  moduleHeader: {
    title: W.layout.staticOrVariable.static("Claims Operations"),
    orientation: W.layout.moduleHeader.orientation.horizontal(56),
    logo: W.layout.moduleHeader.logo.icon("shield", "#1F4B99"),            // top-left
    backgroundColor: W.layout.moduleHeader.backgroundColor("#1F4B99", "PROMINENT"),
    startComponents: [navButtons],   // ≤ 5 primary destinations
    endComponents: [settingsButton], // global settings top-right
  },
};
```

Pin section navigation with tabs. **Tabs only render if their section has a header**, so always pair `tabbed` with a section header and `showTabHeader: true`.

```ts
const tabbedNav = W.layout.section(
  W.layout.layoutDefinition.tabbed(
    [
      { displayName: "Overview", content: overviewSection },
      { displayName: "Queue", content: queueSection },
      { displayName: "Reports", content: reportsSection },
    ],
    { showTabHeader: true },
  ),
  W.layout.section.header({
    title: W.layout.staticOrVariable.static("Claims"),
    description: W.layout.staticOrVariable.static(""),
    height: W.layout.section.headerHeight.auto,
    alignWithSectionPadding: true,
    leadingText: W.layout.staticOrVariable.static(""),
    bold: true,
  }),
  { editorLabel: "Tabbed nav" },
);
```

## 6. Avoid horizontal scrolling; pin navigation
Prefer `fitColumnsHorizontally` on tables over page‑wide horizontal scroll. Keep nav/tabs in the primary header so only content scrolls.

```ts
W.widget.objectTable(
  {
    "Input data": { objectSet: claims, scenarioLoad: { primary: { type: "none" }, comparison: undefined } },
    // ...column configuration...
    "Display & Formatting": {
      // ...other display fields...
      fitColumnsHorizontally: true, // avoids horizontal scrolling
    },
    // ...
  },
  { editorLabel: "Claims table" },
);
```
Filters go in the left column via `W.widget.filterList(...)` with `layout: { type: "vertical" }` for a left rail, or `{ type: "pills" }` for a top filter bar.

## 7. Reduce overload: collapse, defer, and use overlays
When a view approaches the limits, move secondary content out of the primary flow.

```ts
// Collapse secondary content by default
{
  editorLabel: "Advanced filters",
  collapsible: W.layout.collapsible({ hideHeaderWhenCollapsed: false, isInitiallyCollapsed: true }),
}

// Render heavy widgets only when scrolled on-screen (declutter + performance)
{ editorLabel: "Heavy chart", renderBehavior: W.layout.renderBehavior.onScreen() }
```

Use overlays for **temporary/secondary** interactions (forms, detail views) — not for analytical views where users compare layers at once. Design overlays to assume the user selected object(s) first. Open/close them with overlay events.

```ts
const detailsDrawer = W.layout.overlay.drawer(
  {
    title: "Claim details",
    icon: "document",
    position: "right",
    size: "large",
    hasBackdrop: true,
    body: W.layout.layoutDefinition.columns([
      { width: W.layout.size.flex(1), content: detailsSection },
    ]),
  },
  { displayName: "Claim details drawer", id: "claimDetails" },
);

// Trigger from a row action / button via an event:
// { type: "overlayEffect", overlayId: "claimDetails", effectId: "OPEN_DRAWER" }
```

## 8. Validate the design
- **Squint test:** the most important element should still stand out.
- **Workflow check:** every section maps to something the user is trying to do.
- **Necessity check:** if an element isn't needed here, surface it only when the user needs it (collapse, tab, or overlay it).
- **Count check:** ≤ 10 visible components, ≤ 5 nav items, 30–40% whitespace, one elevated area.

## 9. Component-specific best practices
Apply these when configuring the individual widgets, on top of the layout rules above.

### Tables & lists (`objectTable`, `objectList`, `pivotTable`)
- **Always show a count** of rows in the table's section header, via a **Tag**‑style `metricCard` backed by a `count` aggregation — users should see how long the list is at a glance.
- Render **enough per row to make a selection**; put extra detail in a **collapsible side panel**, not an overlay (overlays hide the list users are working from).
- Follow the scrolling rules (section 6): prefer `fitColumnsHorizontally`; keep `numLinesPerRow: 1` for dense tables.

```ts
// Count over the (filtered) object set...
const rowCount = W.variable.objectSetAggregation({
  displayName: "Row count",
  returnType: W.dataType.numeric(),
  objectSet: filteredAccounts,
  metric: W.metric.count(),
});

// ...shown as a compact Tag chip, placed in the section header via rightComponents
const countChip = W.widget.metricCard(
  {
    title: "",
    metrics: [{
      label: { type: "static", static: "Accounts" },
      shortDescription: { type: "static", static: "" },
      hideShortDescriptionInfoIcon: true,
      valueConfig: { type: "variableConfig", variableConfig: { type: "numberConfig", numberConfig: {
        value: rowCount,
        format: { type: "valueFormat", valueFormat: { textColor: { type: "default" }, backgroundColor: { type: "default" }, iconColor: { type: "default" } } },
      } } },
      contextConfig: { type: "noContext" },
      visualizationConfig: { type: "noVisualization" },
      interaction: { type: "noInteraction" },
    }],
    layout: { type: "tag", tag: "HORIZONTAL" }, // Tag = compact count chip; tag is "HORIZONTAL" | "VERTICAL"
    metricSize: "COMPACT",
  },
  { editorLabel: "Row count chip" },
);
// then: W.layout.section.header({ /* ... */, rightComponents: [countChip] })
```

### Button groups (`buttonGroup`)
Match each button's `color` intent to the action's meaning, and use **one** colored (primary) button per group — do not color every button.

| `intent` | Hue | Use for | Examples |
| --- | --- | --- | --- |
| `NONE` | gray | secondary actions | Back, Skip, Cancel |
| `PRIMARY` | blue | main call to action / advance | Create, Add new, Next |
| `SUCCESS` | green | completion / positive outcome | Submit, Save, Approve |
| `WARNING` | amber | needs attention / moderate risk | Archive, Suspend |
| `DANGER` | red | destructive / critical | Delete, Remove |

- **Order left→right by importance**, primary action first; de‑emphasize the rest (e.g. behind a menu).
- **Add icons**; use an arrow icon for navigation — a horizontal arrow for a page/section inside the module, an angled arrow for a new tab/window.
- **Labels** in sentence case and natural language; don't repeat the section title in the button.
- **Proximity:** put the button in the header of the specific widget/section it acts on (e.g. "Add part" in the Parts table header), not a distant global toolbar.

```ts
const tableActions = W.widget.buttonGroup(
  {
    "Button type": { type: "buttonBarConfig" },
    "Button configuration": [
      // Primary action FIRST — the single colored button in the group
      { displayConfig: { text: { type: "static", static: "Log outreach" }, color: { type: "intent", intent: "PRIMARY" }, leftIcon: "add", description: { type: "static", static: "Record a new touch" } }, clickConfig: { type: "workshopEvent", workshopEvent: [] } },
      // Secondary actions stay NONE (gray)
      { displayConfig: { text: { type: "static", static: "Export" }, color: { type: "intent", intent: "NONE" }, leftIcon: "export", description: { type: "static", static: "Download CSV" } }, clickConfig: { type: "workshopEvent", workshopEvent: [] } },
    ],
    "Display & formatting": { orientation: { type: "horizontal" }, fill: "RIGHT", style: { type: "outline", outline: { size: "SMALL", groupButtons: true } } },
  },
  { editorLabel: "Table actions" },
);
```

### Searching & filtering (`filterList`, exploration widgets)
- **Vertical** `filterList` layout when users apply **several filters at once** or filtering is complex — it gives a clear overview; best for the left rail.
- **Pills** layout for compact, beginner‑friendly filtering, limited screen space, or frequent filter changes; best for a top bar.
- Add an **Exploration Search Bar** for comprehensive/precise querying (keyword + property + complex queries) for power users.

```ts
// Left rail — vertical (many simultaneous / complex filters)
"Filters configuration": { filterSections: [/* ... */], enableEndUserToAddFilters: true, layout: { type: "vertical" } }

// Top bar — pills (compact / frequent changes)
"Filters configuration": { filterSections: [/* ... */], enableEndUserToAddFilters: true, layout: { type: "pills" } }
```

## 10. Choosing between components (decision guide)
Quick heuristics for common "which one?" decisions.

- **Object Table vs Object List** — `objectTable` for data with **multiple attributes/columns** (comparison, sorting, bulk actions); `objectList` for **simpler, linear** content with few attributes (fast review, single‑item actions).
- **Modal vs drawer overlay** — a centered **modal** (`W.layout.overlay.modal`) for **critical, focus‑demanding** tasks (confirmations, alerts, action forms); a **drawer** (`W.layout.overlay.drawer`) for **secondary/supplementary** content (details, settings) so the main content stays visible for reference.
- **Collapsible vs hidden (button/variable‑revealed) section** — a **collapsible** section (`W.layout.collapsible`) when users toggle content while keeping its **location visible** (ideal for side panels and filters); **hide + reveal** a section when its content is **only relevant for certain actions/use cases**, or when space is tight and a collapsible is already in use. **Never stack collapsible sections.**
- **Show a side panel by default?** Yes when its content is **essential/frequently used** (navigation, critical metrics), the UI is simple, and users are on large screens. Otherwise make it **collapsible or hidden** — especially for optional/secondary content or small screens.
- **Embed a module** to split a large one — separate logic, reduce the variable count in a single module, or reuse an interface across multiple pages. Prefer embedding over one giant module with many independent pages.
- **Mobile** — if the app targets mobile, follow the mobile design best practices (denser layout, larger touch targets, fewer simultaneous components).

## DSL gotchas
- The returned `page` is the default; create more with `W.layout.page(...)`.
- `editorLabel` is required on every widget and section.
- Never generate new `id`s / `apiName`s or `unsupportedWorkshopConfig` references — only reuse existing ones.
- `tabbed` layouts need a section **header** to be visible (`showTabHeader: true`).
- Column `width` = `absolute` | `flex` only; row `height` may also be `auto`.
- `content` is `Widget | Section` — wrap widgets in sections to get headers, padding, and elevation.
- `headerText` is for header/toolbar slots; use `markdown` for body copy.
- Apply the elevated/shaded style to only one area per page.
- `pivotTable`'s `pivotConfig` is an **unsupported config** (not DSL‑configurable). For a segment × stage style matrix, use an `objectTable` grouped by the row property (`Display & Formatting.groupBy`) with the column property shown as a color‑coded cell, or a chart.
- `metricCard` number/string `format` objects must be **inlined at each metric** — extracting them into a shared `const` widens the `"valueFormat"` literal to `string` and fails type‑checking. The same applies to other discriminated‑union literals (e.g. the metric‑card `layout.tag` value is the string `"HORIZONTAL"`/`"VERTICAL"`, not an object): keep them inline.
- Data‑backed widgets read from **object‑set variables**; drive tables + KPIs from one `filteredAccounts` set (base + `filter.byVariable(<filterListOutput>)`) so the filter list controls everything. KPI numbers come from `W.variable.objectSetAggregation({ ..., metric: W.metric.count()/sum({propertyId}) })`.

I use the grill me skill a bunch. It helps me refine my rough ideas and plans before executing. Reduces the downstream iterations I need
https://github.com/mattpocock/skills/blob/main/skills/productivity/grilling/SKILL.md