Skip to content
AI & Agents
Skill

/workfront-actions

Use when writing or fixing the server-side code of a Workfront App Builder extension — the Adobe I/O Runtime action the React SPA calls to do work the browser can't. Reach for this whenever the user is: structuring or editing action code; deciding what shape an action returns so

From plugin
adobe-skills
162160 skills6 agents4 MCP
Install
$ npx -y skills add adobe/skills --skill workfront-actions --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/workfront-actions

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when writing or fixing the server-side code of a Workfront App Builder extension — the Adobe I/O Runtime action the React SPA calls to do work the browser can't. Reach for this whenever the user is: structuring or editing action code; deciding what shape an action returns so

SKILL.md

workfront-actions.SKILL.md
name: workfront-actions
description: "Use when writing or fixing the server-side code of a Workfront App Builder extension — the Adobe I/O Runtime action the React SPA calls to do work the browser can't. Reach for this whenever the user is: structuring or editing action code; deciding what shape an action returns so the frontend can tell success from failure (the {data,error} body); passing the IMS token through and calling an external API from the backend so credentials never reach the browser; calling Workfront's own Public API v21 (search/count, bulk PUT with the updates param, custom DE: field filters); calling Workfront Planning or another Adobe service; or troubleshooting why a deployed action can't read secrets (process.env is empty once deployed — inputs flow .env → config inputs → params). Also covers CommonJS-only structure, require-adobe-auth, and registering actions in app.config.yaml / ext.config.yaml. For generic non-Workfront action templates and SDKs see appbuilder-action-scaffolder."
license: Apache-2.0

Workfront Runtime actions

Actions are the **back end** — small functions Adobe runs in its cloud on demand ("serverless"; Adobe I/O Runtime, built on OpenWhisk). The front end (SPA, see `workfront-ui-extension`) calls them via `actionWebInvoke`; they hold the credentials and call external APIs. **The browser must never call Workfront/Adobe APIs directly** — that is the action's job, so login tokens never reach the user's browser.

> For generic action *patterns and templates* (webhook receiver, database CRUD, custom event provider, journaling consumer, large-payload redirect, action sequence, Asset Compute worker) and the App Builder SDKs (State/Files/Events/DB), use **`appbuilder-action-scaffolder`**. This skill is the **Workfront-specific** layer: the `{data,error}` contract, IMS passthrough, and Workfront's own Public API.

Anatomy

actions/<name>/index.js     # exports main(params)
  • **CommonJS only** — export your function as `exports.main`. (App Builder supports only CommonJS, not ES Modules.)
  • Register every action in `app.config.yaml`, or in an extension's `ext.config.yaml` (which compiles into `app.config.yaml`), following the OpenWhisk wskdeploy YAML spec.
async function main (params) {
  // ...
  return { statusCode: 200, body: { data, error: null } }
}
exports.main = main

Response shape

Always return `{ data, error }` in the body; the UI checks `error` before using `data`.

return { statusCode: 400, body: { data: null, error: 'missing parameter(s) ...' } }

Auth & inputs

  • **`require-adobe-auth` is a per-action choice, *off* by default** (the platform default) — decide deliberately, don't blanket-enable it. When `true`, Adobe validates the user's IMS token at the gateway before your code runs.
  • Turn it **on** when the action itself is the security boundary (privileged work, or nothing downstream authorizes the caller).
  • Leave it **off** when the downstream API enforces its own authorization — e.g. the action just forwards the user's `imsToken` to Workfront/Planning, which rejects bad tokens — or unless explicitly asked to enable it.
  • The UI passes `imsToken` (→ `Authorization: Bearer …`) and the Workfront instance URL as **params**; never hardcode them.
  • **The IMS org id is in the shared context at `auth.imsOrgID`** (capital `ID` — not `imsOrgId`/`imsOrg`; that casing trap costs hours). The front end reads `sharedContext.get('auth').imsOrgID` and passes it down; the action uses `params.imsOrgId` / the `x-gw-ims-org-id` header. Two traps: (1) **reject the strings `"undefined"`/`"null"`/empty** — an empty front-end value becomes the header string `"undefined"` (→ `401 "Org Id undefined is not in the list of user org Ids"`); (2) with `require-adobe-auth: true` the gateway validates the org header *before* your code runs.
  • **Inputs flow `.env` → action `inputs` (in config) → `params`. Do NOT read `process.env` at runtime.** Under `aio app dev` actions run in-process, so `process.env` may *appear* to work locally but will be empty once deployed. Wire keys/secrets as `inputs` and read them from `params`.

Calling external APIs (the pattern)

For any API — Workfront, Planning, Adobe services:

1. Receive `imsToken` plus any `apiKey` / IDs as `params`. 2. `fetch` the **public** REST endpoint with `Authorization: Bearer <imsToken>` (add `x-api-key` / `x-gw-ims-org-id` where required). 3. Map the result to `{ data, error }`. Never log the token.

  • **Workfront Planning** → **verify the Workfront MCP is connected, then fetch the v2 endpoint reference and data from it** (details in `references/integrations.md`); if it isn't connected, stop and tell the user to connect the Workfront MCP before continuing. **Other Adobe services** → `references/integrations.md`. Confirm endpoints from the live source rather than guessing.

Workfront Public API v21.0

Workfront's own REST API — the `/attask/api/v21.0` layer. Call it from an action (never from the SPA).

  • **wfClient / base URL:** `{workFrontInstanceUrl}/attask/api/v21.0{path}` — a single version constant. `workFrontInstanceUrl` and `imsToken` arrive as **params** (never hardcoded).
  • **Search / count** objects (projects, tasks, issues) via the documented query params; map the response into `{ data, error }`.
  • **Custom `DE:` fields** need `{field}_Mod=notblank` on search/count, or they are silently omitted from results.
  • **Bulk update** with `PUT /{obj}?updates=[...]` (the `updates` array in the query string) — **chunk** requests to stay under the ~8 KB URL-length limit; fall back to per-record `PUT /{obj}/{ID}` when a chunk is still too long.
  • Wrap the calls in a small `wfFetch` helper; register the action in `app.config.yaml`; the SPA reaches it via `actionWebInvoke` only.

Time budget

The action the SPA calls via `actionWebInvoke` is a **web action**, so it's bound by Adobe I/O Runtime's **60 s cap** on web/blocking actions — raising `limits.timeo

Read more
Ships withadobe-skills

Repository of Adobe skills for AI coding agents.

Get the whole plugin

Other skills on adobe-skills.