temporal-ts-enriching-ui

star 0

Use when adding metadata (summaries, details) to Temporal Workflows, Activities, or Timers in TypeScript to enrich the Temporal Web UI. Covers staticSummary, staticDetails, setCurrentDetails, activity executeWithOptions, and timer summary options. Applies to any project using @temporalio/client or @temporalio/workflow.

remodlai By remodlai schedule Updated 3/3/2026

name: temporal-ts-enriching-ui version: 1.0.0 description: > Use when adding metadata (summaries, details) to Temporal Workflows, Activities, or Timers in TypeScript to enrich the Temporal Web UI. Covers staticSummary, staticDetails, setCurrentDetails, activity executeWithOptions, and timer summary options. Applies to any project using @temporalio/client or @temporalio/workflow.

Temporal TypeScript SDK -- Enriching the UI

Temporal lets you attach human-readable metadata to Workflows, Activities, and Timers. This metadata appears in the Temporal Web UI, making it easier to identify and understand what each Workflow is doing without inspecting payloads.

There are three distinct mechanisms:

Mechanism Where Set Mutability Scope
staticSummary Client, at Workflow start Immutable after start Workflow list view
staticDetails Client, at Workflow start Immutable after start Workflow detail view
setCurrentDetails() Inside Workflow code Updatable at any time Workflow detail view
Activity staticSummary Inside Workflow, via executeWithOptions Immutable per invocation Event history
Timer summary Inside Workflow, via sleep options Immutable per invocation Event history

When to Use

  • You want Workflow list views to show a short description instead of just a Workflow ID.
  • You want the detail page to show context about the Workflow's current state.
  • You want Activity and Timer events in the history to be self-documenting.
  • You are building an operator dashboard or need better observability for non-engineers.

How to Use

Environment Context Gathering

Before implementing, determine the user's Temporal setup:

  1. Where is Temporal running? (local dev server via temporal server start-dev, self-hosted cluster, or Temporal Cloud)
  2. What is the full Temporal UI URL? Default local: http://localhost:8233. If not local, get the full URL.
  3. Is ingress configured for the Temporal HTTP API? This matters for Temporal Cloud or Kubernetes-hosted clusters where the HTTP API endpoint may differ from the gRPC endpoint.

These answers affect how the user views the enriched UI metadata after implementation.

Quick Reference

API Import Limit
staticSummary @temporalio/client (on WorkflowStartOptions) 200 bytes
staticDetails @temporalio/client (on WorkflowStartOptions) 20,000 bytes
getCurrentDetails() @temporalio/workflow --
setCurrentDetails(value) @temporalio/workflow 20,000 bytes
activity.executeWithOptions({ staticSummary }, args) @temporalio/workflow (on proxy) 200 bytes
sleep(duration, { summary }) @temporalio/workflow 200 bytes

Format: Standard Markdown (no images, no HTML, no scripts).

Implementation Patterns

1. Set Static Summary and Details at Workflow Start

Use staticSummary and staticDetails when starting a Workflow from the client. These are immutable once set.

import { Client } from '@temporalio/client';

const client = new Client();

const handle = await client.workflow.start(orderWorkflow, {
  args: [orderPayload],
  taskQueue: 'orders',
  workflowId: `order-${orderId}`,
  staticSummary: `Order #${orderId} for ${customerName}`,
  staticDetails: [
    `**Customer:** ${customerName}`,
    `**Items:** ${itemCount}`,
    `**Shipping:** ${shippingMethod}`,
  ].join('\n'),
});

Works identically with client.workflow.execute(...).

2. Update Current Details Inside a Workflow

Use setCurrentDetails to reflect the Workflow's progress as it runs. Call it as many times as needed.

import { getCurrentDetails, setCurrentDetails } from '@temporalio/workflow';

export async function orderWorkflow(order: Order): Promise<string> {
  setCurrentDetails(`## Order ${order.id}\nStatus: **validating**`);

  await validateOrder(order);
  setCurrentDetails(`## Order ${order.id}\nStatus: **charging payment**`);

  await chargePayment(order);
  setCurrentDetails(`## Order ${order.id}\nStatus: **shipping**`);

  await shipOrder(order);
  setCurrentDetails(`## Order ${order.id}\nStatus: **completed**`);

  return 'done';
}

3. Add Summary to Activity Calls

Use executeWithOptions on the proxied activity. Note: arguments go in an array as the second parameter.

import { proxyActivities } from '@temporalio/workflow';
import type * as activities from './activities';

const { sendEmail, chargeCard } = proxyActivities<typeof activities>({
  startToCloseTimeout: '30 seconds',
});

export async function checkoutWorkflow(input: CheckoutInput): Promise<void> {
  await chargeCard.executeWithOptions(
    { staticSummary: `Charge $${input.amount} to card ending ${input.lastFour}` },
    [input],  // arguments as array
  );

  await sendEmail.executeWithOptions(
    { staticSummary: `Confirmation email to ${input.email}` },
    [input.email, input.receiptId],
  );
}

4. Add Summary to Timers

Pass an options object with summary as the second argument to sleep.

import { sleep } from '@temporalio/workflow';

export async function trialWorkflow(userId: string): Promise<void> {
  await sleep('7 days', { summary: `7-day trial period for user ${userId}` });
  // trial expired, proceed
}

Common Mistakes

  1. Exceeding the 200-byte limit on summaries. The summary silently truncates. Keep summaries short and ASCII-friendly (multi-byte characters eat the budget fast).

  2. Passing activity args as positional parameters instead of an array.

    // WRONG -- args are positional
    await myActivity.executeWithOptions({ staticSummary: '...' }, arg1, arg2);
    
    // CORRECT -- args in an array
    await myActivity.executeWithOptions({ staticSummary: '...' }, [arg1, arg2]);
    
  3. Using staticSummary / staticDetails inside the Workflow. These are client-side options only. Inside the Workflow, use setCurrentDetails().

  4. Including images, HTML, or script tags in Markdown. These are stripped. Stick to text formatting: bold, italic, headers, lists, links.

  5. Forgetting that staticSummary and staticDetails are immutable. If you need the detail to change over time, use setCurrentDetails() instead of or in addition to the static fields.

  6. Calling getCurrentDetails() expecting it to return staticDetails. getCurrentDetails only returns the value set by setCurrentDetails. Static details are separate and read-only from the UI.

Debugging Tips

  • Summary not appearing in the UI? Check the byte length. Use Buffer.byteLength(summary, 'utf8') to verify it is under 200 bytes.
  • Details not rendering Markdown? Ensure you are not using images, HTML, or <script> tags. Only standard Markdown text formatting is supported.
  • setCurrentDetails not updating? The UI polls; refresh the page. Also confirm the Workflow has actually reached the line that calls setCurrentDetails.
  • Activity summary missing from event history? Make sure you used executeWithOptions and not the normal direct call syntax. The standard await myActivity(args) call does not accept summary options.
  • Timer summary not showing? Verify you are passing the options object as the second argument to sleep, not as part of the duration string.

Further Reading

If this skill does not answer your question, use Context7 to search /temporalio/sdk-typescript or /temporalio/samples-typescript for more details.

Install via CLI
npx skills add https://github.com/remodlai/skills-temporal --skill temporal-ts-enriching-ui
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator