Temporal Ops
OpenAIOfficialCreated by TemporalDistributed by OpenAI
- Skill
- Tool integration
- Cloud and DevOps
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to managing and troubleshooting Temporal environments. It covers two primary modes: Operations, for administrative tasks like namespace management, API key rotation, and batch workflow actions; and Diagnosis, for investigating issues like stuck workflows, connectivity errors, and performance bottlenecks. It enforces strict operational discipline, including explicit confirmation for destructive commands and a bottom-up diagnostic methodology to ensure root causes are identified accurately.
What it does
- Performs administrative operations on Temporal Cloud via tcld and self-hosted clusters via temporal operator.
- Executes batch operations on workflows using query-based filtering with safety-first confirmation steps.
- Diagnoses system issues using a layered, bottom-up approach from network connectivity to workflow logic.
- Manages security configurations including API keys, mTLS certificates, and SAML/SCIM integrations.
- Provides guidance on interpreting audit logs and cloud capacity metrics.
- Routes complex tasks to specialized skills for development, worker tuning, or infrastructure configuration.
When to use it
- When you need to perform administrative tasks like creating namespaces or rotating credentials.
- When a Temporal environment is experiencing errors such as connection timeouts or authentication failures.
- When you need to investigate or recover from stuck, non-deterministic, or unhealthy workflows.
- When you need to perform bulk operations on workflows and require a safe, verified execution process.
- When you need to audit or monitor the health and capacity of your Temporal Cloud account.
Advantages
- Enforces safe operational practices by requiring explicit approval for destructive commands.
- Provides a systematic diagnostic ladder to avoid speculative fixes.
- Distinguishes clearly between Cloud and self-hosted administrative procedures.
- Integrates safety checks like counting affected workflows before executing batch mutations.
- Standardizes the interpretation of common gRPC and Temporal-specific error codes.
Usage examples
- “How do I rotate my mTLS certificates for my Temporal Cloud namespace?”
- The agent will guide you through the tcld commands for generating new certificates and updating the namespace configuration, ensuring you follow the correct rotation sequence.
- “I am seeing 'context deadline exceeded' errors in my workflow. How do I debug this?”
- The agent will initiate a bottom-up diagnosis, starting by verifying network connectivity and gRPC health before investigating specific workflow task execution logs.
- “Terminate all workflows of type 'OrderProcessing' that are currently stuck.”
- The agent will first run a count to identify the number of affected workflows, present this number to you for confirmation, and then execute the batch termination only after your approval.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/openai/temporal-ops/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip temporal-ops.zip -d .agents/skills
Documentation by Temporal
Skill: temporal-ops
Overview
This skill operates and diagnoses Temporal environments. It has two modes:
Operations: the user wants to do something — create a namespace, rotate a key, check capacity, find unhealthy workflows, cancel a batch, set up export. The skill executes the right commands and interprets the output.
Diagnosis: the user arrives with a symptom — a stuck workflow, a cert error, a connection timeout, a non-determinism panic. The skill routes the investigation through a layered, bottom-up diagnosis until a root cause is identified with a confidence score.
It does not teach how to write workflows or activities (use skill-temporal-developer for that), and it does not reproduce exhaustive CLI flag tables — run temporal <cmd> --help for those, and see cli-conventions.md for cross-command CLI conventions. The boundary is: if the user needs to administer or troubleshoot a running Temporal environment, this skill applies.
Out of scope
Writing workflows, activities, or SDK code →
skill-temporal-developer.Exhaustive CLI flags / command reference → run
temporal <cmd> --help; cross-command CLI conventions → cli-conventions.md.Worker performance tuning, sizing, capacity planning →
skill-temporal-workertuning.Helm, Kubernetes, database admin, monitoring stack config for self-hosted — beyond the CLI surface.
If the conversation drifts into one of these areas, hand off to the relevant sibling skill rather than improvising.
Philosophy
Operator discipline
When the user wants to perform an operational task:
Identify the intent and backend. Is this a Cloud operation (
tcld) or a self-hosted operation (temporal operator)? Data-plane operations (temporal workflow,temporal batch, etc.) work on both. If the backend is ambiguous, ask before proceeding — do not assume Cloud or self-hosted and do not output environment-specific commands until you know.Execute commands and interpret output. Run the documented command, read the result, and report what it means — or act on it if the user asked for an action. Read-only commands (
get,list,describe,count,show) run freely. Anything listed under Destructive operations is proposed to the user first.Verify the result. After a mutating operation, confirm the new state matches the user's intent.
Destructive operations
An operation belongs to this tier if it is irreversible (tcld namespace delete), revokes access for a live identity (tcld apikey delete), moves
production traffic (tcld namespace failover), or fans out to every match
(any --query form). Apply the test to the operation in front of you — this is a
rule, not a list, and a command's absence from any list in this skill does not
place it outside the tier.
For anything in the tier: gather the evidence and propose. Do not run it on your own initiative, and do not run one to find out what it would do. The reference file for each command states its specific blast radius; read that before proposing, not after.
Blast radius as a number, not a description. For any
--queryform, runtemporal workflow count --query '<query>'with the byte-identical query first and carry the result into the proposal. A filter with no narrowing predicate beyondExecutionStatus="Running"matches every open Execution in the Namespace.Name the target. State the exact command, the target, and the Namespace it resolves to. Connection settings can come from
TEMPORAL_*env vars or a config-file profile, so the target is frequently not visible in the command text. If the backend or Namespace was inferred from context rather than stated by the user, say so — a destructive command aimed at the wrong Namespace is the most common way this goes wrong.Ask explicitly, then run it so it completes. Put the command, the target, and — for any
--queryform — the count from step 1 to the user as a direct question, and wait for an answer. Once they approve, run it with--yeson the--querybatch forms; that flag is what lets an approved batch finish, since the interactive prompt needs a terminal and without one the command reportsuser denied confirmationand does nothing.--yesbelongs in a command the user approved, never in a retry of one that failed its prompt. Do not substitute a loop over single-targetworkflow terminate --workflow-id. Approval covers one command against one target; it does not carry to the next command, a widened query, or a second Namespace.Verify, and know the abort path. Re-run the corresponding
get,describe, orcount. A batch job drains asynchronously:temporal batch describe --job-id <id>shows how far it has gotten andtemporal batch terminate --job-id <id>stops it before it reaches the rest of its matches.
When a reversible sibling reaches the same goal, propose it alongside: cancel
lets Workflow cleanup code run where terminate does not; apikey disable is
reversible where delete is not; accepted-client-ca add appends where set
replaces.
Assume nothing in the environment will stop a destructive command on your behalf. Credential scope, command denylists, and confirmation prompts may or may not be configured, and their possible presence is not a reason to skip any step above — you are the safeguard the user is relying on.
Diagnostic discipline
When the user arrives with a failure or anomaly:
Bottom-up diagnosis. Verify the lower layer before blaming the upper one. The layers, from bottom to top:
DNS / network path
TCP / port reachability
TLS handshake
Authentication (API key or mTLS client cert)
gRPC health and Temporal frontend reachability
Temporal namespace, task queues, workers
Workflow code (determinism, signals, timers, child workflows)
The full ladder lives in diagnostic-ladder.md.
Always verify the next layer up rather than prescribing a speculative fix. If TLS works, prove auth works before blaming the workflow. If pollers are present, prove the workflow's last event before blaming the worker.
Attach a confidence score (1-10) to every proposed diagnosis:
9-10: symptoms, operation, and confirming signals line up cleanly.
6-8: evidence is good but at least one alternative remains plausible.
1-5: the issue is still ambiguous; the "fix" is the next discriminating check, not a root cause.
Name ambiguity explicitly. Errors like
context deadline exceededare not self-describing, and a single code such asRESOURCE_EXHAUSTEDcan mean more than one condition (account-limit throttling vs. per-Workflow lock contention). Surface that, gather more context, and scope the next step narrowly.
These are skill conventions, not docs-derived facts.
Intent routing
Operations
Find the row that matches the user's intent. The reference file contains the commands and procedures.
| Intent | Category | Reference |
|---|---|---|
| Create, get, list, delete a Cloud namespace | Cloud namespace admin | cloud-namespace-admin.md |
| Add/remove region, failover, HA config | Cloud namespace admin | cloud-namespace-admin.md |
| Set retention, tags, codec-server, connectivity rules | Cloud namespace admin | cloud-namespace-admin.md |
| Add or rename Cloud search attributes | Cloud namespace admin | cloud-namespace-admin.md |
| Check current APS / capacity mode | Cloud capacity | cloud-capacity.md |
| Switch On-Demand ↔ Provisioned, set TRUs | Cloud capacity | cloud-capacity.md |
| Understand APS / RPS / OPS limits and throttling | Cloud capacity | cloud-capacity.md |
| Create, disable, enable, delete an API key | Cloud IAM | cloud-iam.md |
| Invite, list, remove users; set roles/permissions | Cloud IAM | cloud-iam.md |
| Manage user groups and service accounts | Cloud IAM | cloud-iam.md |
| Generate mTLS certs, upload CA, set cert filters | Cloud certs | cloud-certs.md |
| Rotate mTLS certificates | Cloud certs | cloud-certs.md |
| Set up Workflow History Export (S3 / GCS) | Cloud namespace admin | cloud-namespace-admin.md |
| Set up PrivateLink / PSC, manage connectivity rules | Cloud connectivity | cloud-connectivity.md |
| Self-hosted cluster health, describe, namespace CRUD | Self-hosted admin | self-hosted-admin.md |
| Self-hosted search attributes, Nexus endpoints | Self-hosted admin | self-hosted-admin.md |
| Check or manage a Cloud Nexus Endpoint's caller-Namespace allowlist; the 1,000-caller default | Cloud namespace admin | cloud-namespace-admin.md#tcld-nexus-endpoint-allowed-namespace |
| Find stuck/hung/unhealthy workflows via list queries | Workflow health | workflow-health.md |
| Task queue poller status, workflow counts | Workflow health | workflow-health.md |
| Cancel, terminate, or reset workflows | Workflow recovery | workflow-stuck.md#recovery-commands |
Bulk / batch operations on workflows (--query) | CLI conventions | cli-conventions.md |
| Schedule CRUD, time-spec, and operations | CLI conventions | cli-conventions.md |
| Complete or fail an activity externally | CLI conventions | cli-conventions.md |
| Cloud Ops API access, rate limits, Go SDK | Cloud Ops API | cloud-ops-api.md |
| View billing, generate billing report, cost attribution | Cloud billing | cloud-billing.md |
| Audit Logs: view, query via API, configure sink (AWS/GCP) | Cloud audit logs | cloud-audit-logs.md |
| Terraform provider: Namespace/User/SA/API Key/Nexus CRUD | Cloud Terraform | cloud-terraform.md |
| Expiry alerts (cert, API key, credit), status page | Cloud notifications | cloud-notifications.md |
| SAML SSO, SCIM provisioning, IdP integration | Cloud SAML/SCIM | cloud-saml-scim.md |
| Migrate self-hosted to Cloud (automated or manual), migrate between Cloud regions | Cloud migration | cloud-migration.md |
| End-to-end ops playbook (setup, rotation, audit, billing, Terraform) | Ops recipes | ops/recipes.md |
Diagnosis
Find the row that matches the user's symptom. Start the investigation at the first check, then read the linked reference.
| Symptom | Category | First check | Reference |
|---|---|---|---|
connection refused, cannot reach frontend | Connectivity | nc -zvw10 <host> 7233 | connectivity.md#connection-refused |
no such host, DNS resolution fails | Connectivity | dig +short <host> or nslookup <host> | connectivity.md#dns |
tls: handshake failure, server rejects handshake | Certificates | openssl s_client -connect <host>:7233 -servername <host> </dev/null | certificates.md#handshake-failure |
x509: certificate has expired or not yet valid | Certificates | openssl x509 -enddate -noout -in cert.pem | certificates.md#expired-or-not-yet-valid |
x509: certificate signed by unknown authority | Certificates | openssl verify -CAfile ca.pem client.pem | certificates.md#unknown-authority |
tcld session / auth fails, Cloud role unclear | Authentication | tcld account get | authentication.md#cloud-role-and-permission-model |
UNAUTHENTICATED, API key rejected | Authentication | env | grep -i TEMPORAL_API_KEY, then tcld apikey get --id <apikey_id> | authentication.md#things-to-check-when-unauthenticated-is-returned-with-an-api-key |
namespace not found / wrong namespace string with an API key | Authentication | Confirm Regional Endpoint form <region>.<cloud_provider>.api.temporal.io:7233 | authentication.md#address-form-for-api-key-connections |
RESOURCE_EXHAUSTED gRPC status | Rate limits | Identify which limit fired: throttle metrics on Cloud v1, the resource_exhausted_cause label on v0 / self-hosted | rate-limits.md#identifying-which-limit-was-hit |
| Task queue shows no pollers | Worker health | temporal task-queue describe --task-queue <q> | worker-health.md#what-no-pollers-looks-like |
| Workflow stuck on a pending activity / timer / child / signal | Workflow stuck | temporal workflow describe --workflow-id <id> | workflow-stuck.md#the-primary-inspection-command-temporal-workflow-describe |
NondeterminismError, repeating WorkflowTaskFailed | Non-determinism | Identify the last WorkflowTaskFailed cause in the Event History | non-determinism.md#the-wft-failure-signature-of-non-determinism |
| Replay fails locally but prod workflow was running | Non-determinism | Fetch the history and run the SDK replayer in one test | replay.md#step-2--run-the-sdk-replayer-all-supported-sdks |
| HA failover did not route traffic to failover region | HA failover | tcld namespace get --namespace <ns>.<acct> vs. DNS CNAME | ha-failover.md#start-here-establish-ground-truth |
| Serverless Worker (AWS Lambda) stopped processing work after a Namespace failover | HA failover | Confirm a FailoverNamespace audit event, then compare the new active region against the Lambda ARN on the Worker Deployment Version | ha-failover.md#symptom-serverless-workers-kept-running-in-the-old-region-after-failover |
context deadline exceeded (unknown layer) | Runtime errors | Identify which operation and SDK emitted it | runtime-errors.md#deadline-exceeded |
Workflow is busy / ResourceExhausted on signal/update/query to one Workflow (BusyWorkflow) | Runtime errors | Rule out account-limit throttling, then split temporal_cloud_v1_resource_exhausted_error_count by operation | runtime-errors.md#workflow-lock-contention-busyworkflow |
PAYLOADS_TOO_LARGE, exceeds size limit, payload/gRPC blob size error | Blob size limits | Check whether the issue is payload (2 MB) or gRPC message (4 MB) | blob-size-limits.md |
| Workflow stuck in invisible retry loop (gRPC message too large) | Blob size limits | Check Worker logs for ResourceExhausted, reduce batch size | blob-size-limits.md |
| High schedule-to-start latency, task slot depletion, slow Workflow Tasks | Performance bottlenecks | Check temporal_workflow_task_schedule_to_start_latency P95 | performance-bottlenecks.md |
| High replay latency, cache evictions, deadlock detected | Performance bottlenecks | Check workflow_task_replay_latency and sticky cache metrics | performance-bottlenecks.md |
| Schedule did not fire, missed catchup window | Missed Schedule Actions | Alert on temporal_cloud_v1_schedule_missed_catchup_window_count | schedule-missed.md |
If a symptom does not map to a row, start at diagnostic-ladder.md and work up from whichever layer was last known healthy.
The process
Operations path
Step 1: Identify intent and backend
Determine what the user wants to do and whether it targets:
Temporal Cloud → use
tcldcommands (requirestcld login)Self-hosted cluster → use
temporal operatorcommandsData plane (either backend) → use
temporal workflow,temporal batch,temporal schedule, etc.
If the backend is unambiguous from context — .tmprl.cloud address, tcld command, Cloud namespace format ns.account → Cloud; Kubernetes/Helm, docker-compose, self-hosted config files → self-hosted — proceed without asking. Otherwise, stop and ask: "Are you on Temporal Cloud or self-hosted?" before outputting any environment-specific commands. Do not default to either environment. Once known, save the answer to memory so you don't ask again in future conversations.
Step 2: Execute and interpret
Look up the intent in the Operations table above. Read the linked reference file for the exact commands, flags, and expected output. Run the command and interpret the result for the user.
Step 3: Verify
After a mutating operation (create, update, delete, rotate), confirm the new state:
Re-run the corresponding
getordescribecommandConfirm the output matches the user's intent
Report the result
Diagnosis path
Step 1: Identify the symptom
Ask the user for the exact, copy-pasted error text. Do not accept paraphrases — the exact string often encodes the layer (e.g., x509: prefix means TLS/cert layer, RESOURCE_EXHAUSTED: prefix means gRPC rate limit, NondeterminismError means workflow replay layer). Note that RESOURCE_EXHAUSTED alone does not tell you which condition fired — account-limit throttling and per-Workflow lock contention (Workflow is busy, i.e. BusyWorkflow) share the code. Split the resource-exhausted metric by its label (operation on the Cloud v1 family, resource_exhausted_cause on v0 and self-hosted) rather than parsing the free-text message.
Confirm three things before continuing:
What command was run, or what SDK call produced the error?
What environment produced it (local dev server, self-hosted cluster, Temporal Cloud)? If clear from context (addresses, commands, namespace format), don't ask — but if uncertain, ask now before proceeding with any diagnosis. Save the answer to memory for future conversations.
What changed recently (new deploy, new certs, new namespace, new region)?
Step 2: Gather context
The context the investigation needs depends on the category. At minimum:
For any Cloud auth / connectivity issue: auth method (API key vs mTLS), exact address, exact namespace, SDK + version. The endpoint family differs by auth method — see connectivity.md#endpoint-formats. For private connectivity (PrivateLink / PSC), TLS server name overrides also vary by auth method — see cloud-connectivity.md.
For a stuck workflow: namespace, workflow ID, run ID, and the output of
temporal workflow describe --workflow-id <id>(pending-operation state lives here, not in the Event History alone). Event History viatemporal workflow showis the companion view.For a worker health issue: worker logs (registration errors, auth errors, panics), the output of
temporal task-queue describe --task-queue <q>, andtemporal worker describe --task-queue <q>for per-worker details.For a non-determinism error: the worker log line containing the error, the workflow type name, and access to the history JSON for replay.
Step 3: Validate pasted SDK config (if any)
If the user has pasted SDK connection code — even just the address/namespace/auth fields — review it against sdk-snippet-review.md before descending the ladder. Wrong endpoint family, short namespace, or mismatched auth method will make every network-layer probe below look broken when nothing lower actually is.
Skip this step when the user has an established, previously-working config and the symptom is new — the snippet is not the culprit, the environment changed. Otherwise treat snippet validation as Layer 0.
Step 4: Descend the ladder
Use diagnostic-ladder.md to pick the right starting layer. As a rule of thumb:
Auth / connectivity / cert symptom → start at layer 1 (DNS) and walk up.
Worker / task-queue symptom → start at layer 6 (namespace + pollers).
Stuck workflow / determinism symptom → start at layer 7 (workflow code), but confirm layer 6 (worker is actually polling) first.
Each layer has a command that proves it healthy and a failure signature that tells you whether the problem lives at that layer or higher.
Step 5: Fix and verify
Prescribe the fix scoped to the root cause. Then verify by re-running the layer's healthy-check command and, if possible, the original user operation. Attach the confidence score to the diagnosis.
If the layer above the fix is still failing, return to step 4 and continue walking upward — the first broken layer is rarely the only one.
Prerequisites
Temporal CLI (
temporal) — required for data-plane operations and self-hosted admin. Install:brew install temporalor see Temporal CLI docs.tcld — required for Cloud operations. Install:
brew install temporal-cloud-clior see tcld docs. Authenticate withtcld loginbefore use.
Reference files
Operations
cloud-namespace-admin.md — Cloud namespace lifecycle via
tcld: create, get, list, delete, failover, add-region, retention, tags, codec-server, HA config, connectivity rules, search attributes, accepted-client-ca, certificate filters, export, and thetcld nexus endpoint allowed-namespacecaller allowlist (1,000-caller Access Policy ceiling).cloud-capacity.md — Capacity modes (On-Demand / Provisioned), APS/RPS/OPS definitions, TRUs,
tcld namespace capacity update, default limits, throttling, APS management best practices.cloud-iam.md — API key lifecycle (
tcld apikey), users (tcld user), user groups (tcld user-group), service accounts, account operations (tcld account), roles, namespace permissions.cloud-certs.md — mTLS cert management: generating certs with
tcld generate-certificates, uploading CAs, certificate filters, cert rotation, switching mTLS ↔ API keys.cloud-connectivity.md — Private connectivity (AWS PrivateLink / GCP PSC), connectivity rules: setup, rule parameters, tcld commands, attaching rules to namespaces.
cloud-migration.md — Migration paths: automated self-hosted→Cloud (S2S proxy,
tcld migrationcommands, 5 phases), manual self-hosted→Cloud (client changes, workflow strategies), within-Cloud region-to-region (HA add-region/failover).cloud-ops-api.md — Cloud Ops API: HTTP and gRPC endpoints (
saas-api.tmprl.cloud), Go SDK, protobuf compilation, rate limits (160 RPS account, 40 user, 80 SA, 10 concurrent async), API version header, use cases.cloud-billing.md — Cloud billing: Billing Center (invoices, credits, plans, cost by namespace), Usage Dashboards, Billing API: async CSV report generation, FOCUS-friendly format, 27-column report schema, date range constraints.
cloud-audit-logs.md — Cloud Audit Logs: supported control plane events (Account, API Keys, Connectivity Rules, Namespace, Export, Nexus, Service Accounts, User, User Groups), JSON format, API access (30-day retention), AWS Kinesis and GCP Pub/Sub sink configuration.
cloud-terraform.md — Terraform provider: setup (
TEMPORAL_CLOUD_API_KEY),temporalcloud_namespace/temporalcloud_user/temporalcloud_service_account/temporalcloud_apikey/temporalcloud_nexus_endpointCRUD, import, data sources (regions, namespaces), limitations (API keys not importable, cannot manage Account Owner).cloud-notifications.md — Cloud notifications: certificate expiry (15/10/5 days), API key expiry (30/20/10 days), credit consumption/expiry alerts, plan changes, failover events, recipient roles,
[email protected]sender.cloud-saml-scim.md — SAML SSO (Entra ID, Okta): entity identifier (
urn:auth0:prod-tmprl:ACCOUNT_ID-saml), callback URL (login.tmprl.cloud), IdP configuration steps, support ticket workflow. SCIM: supported vendors, prerequisites (SAML first), 10-minute sync window, group-to-role mapping.self-hosted-admin.md — Self-hosted control plane via
temporal operator: cluster health/describe, namespace CRUD, search-attribute create/list/remove, Nexus endpoint CRUD.workflow-health.md — Data-plane health queries:
temporal workflow listwith List Filters,temporal workflow describe/show/count,temporal task-queue describefor poller status.cli-conventions.md — Cross-command
temporalCLI conventions: connection/identity (TEMPORAL_*env vars ↔--address/--namespace/--api-key,--identity), output/formatting (--output,--time-format, payload shorthand), the--query⇒ batch-job bridge (withtemporal batch describe/list/terminate), and schedule time-spec forms. Ends with an operation→command index that routes each data-plane operation to its owner file. Delegates exhaustive flags totemporal <cmd> --help.ops/recipes.md — End-to-end ops playbooks: set up new namespace, check APS, switch capacity mode, find hung workflows, rotate API key, audit access, rotate mTLS certs, check self-hosted health, view billing / generate billing report, configure audit log sink, provision resources with Terraform, set up SAML SSO.
Diagnosis
sdk-snippet-review.md — Layer-0 config check for pasted SDK connection snippets: endpoint form per auth method, namespace format, auth / TLS expectations,
TEMPORAL_*env vars, common misconfigurations. Run before the diagnostic ladder.diagnostic-ladder.md — the seven-layer bottom-up model, with one canonical command per layer and cross-links into the topical leaves.
connectivity.md — DNS, TCP, endpoint families (Namespace Endpoint for mTLS vs. Regional Endpoint for API keys), firewall/proxy shapes, PrivateLink/PSC, quick diagnostic scripts.
certificates.md — x509 and TLS alert strings, expiry / unknown-authority / hostname-mismatch / key-mismatch diagnosis, Cloud accepted-client-CA set via
tcld namespace accepted-client-ca, Cloud mTLS certificate requirements, rotation and expiry notifications, openssl recipes.authentication.md —
UNAUTHENTICATEDvsPERMISSION_DENIED, API-key lifecycle (tcld apikeycommands, env var propagation, required Regional Endpoint form), mTLS after TLS (certificate filters, identity-to-role mapping), Cloud account-level roles and namespace-level permissions.workflow-stuck.md — Workflow Execution Status values,
temporal workflow describeas the primary inspection command, Event History viatemporal workflow show, pending activities / child workflows / signals / Nexus operations / Workflow Tasks, WorkflowTaskFailed retry loops, recovery commands (signal, terminate, cancel, reset, pause/unpause).non-determinism.md — determinism definition, WFT-failure signature, ND-inducing code patterns, per-SDK error shapes, identifying ND from Event History, local replay reproduction, remediation via Worker Versioning / patching / reset.
worker-health.md — no-pollers runbook via
temporal task-queue describe, reachability and versioning, worker-level describe, schedule-to-start latency, worker task slots, sticky execution and sticky cache, worker heartbeating, Cloud namespace-level poller limits, worker log signatures.rate-limits.md — what
RESOURCE_EXHAUSTEDmeans (and does not), Cloud APS / RPS / OPS under On-Demand and Provisioned capacity modes, self-hostedfrontend.rps/frontend.namespaceRPSdynamic config, identifying which limit fired via the throttle metrics (Cloud v1) or theresource_exhausted_causelabel (v0 / self-hosted), and separating account-limit throttling from single-resource exhaustion.ha-failover.md — Cloud HA routing via the Namespace Endpoint CNAME, verifying the active region (control-plane
tcld namespace getvs. DNS view), clients that did not follow the failover, PrivateLink after failover, failover-not-executing, handover-window errors, platform limits, RPO/RTO semantics, and Serverless Workers (AWS Lambda) not following a failover because compute-provider configuration is region-scoped.runtime-errors.md — deadline-exceeded disambiguated by operation and by where the call was made, Workflow lock contention (BusyWorkflow) separated from account-limit throttling and confirmed via the
operationbreakdown, routing forno pollers/INVALID_ARGUMENT/ unspecifiedUNAVAILABLE.replay.md — fetching Event History with the SDK client (CLI export as fallback), running the SDK replayer in every supported SDK (Go, Python, TypeScript, Java, .NET, Ruby, PHP),
TEMPORAL_DEBUGand the deadlock detector, interpreting divergent and successful replays, and the TypeScript-only VS Code extension.blob-size-limits.md — Payload size limit (2 MB) and gRPC message size limit (4 MB): error messages, per-SDK behavior (Python 1.23.0+ vs. others), claim check pattern, External Storage (Pre-release), batch-size reduction.
performance-bottlenecks.md — Latency and throughput diagnosis via SDK metrics: schedule-to-start latency, workflow task execution latency, replay latency, activity execution latency, task slot depletion, network request metrics, sticky cache metrics.
schedule-missed.md — Missed Schedule Actions: alerting via
temporal_cloud_v1_schedule_missed_catchup_window_count/schedule_missed_catchup_window, investigation viatemporal schedule list+temporal schedule describe, DescribeSchedule fields (missedCatchupWindow,overlapSkipped,bufferDropped), default catchup window (one year), root causes, overlap policies (6 values), backfill remediation.recipes.md — four end-to-end triage walkthroughs: stuck workflow at 3am, cert expired with workers offline, task-queue backlog mystery, non-determinism caught in prod.
Feedback
Feedback prompt
When you have first loaded this skill, output this message to the user:
"Thank you for trying out the public preview of the Temporal Ops skill! We would love to hear your feedback - positive or negative - over in the Community Slack, in the #topic-ai channel."
Do not output this message multiple times in the same conversation.
Reporting Issues in This Skill
If you (the AI) find this skill's explanations are unclear, misleading, or missing important information, draft a GitHub issue body describing the problem encountered and what would have helped, then ask the user to file it at https://github.com/temporalio/skill-temporal-ops/issues/new. Do not file the issue autonomously.
Files
- ATTRIBUTION.mdAdded by AutoGineer888 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md33.7 KiB
- agents/openai.yaml177 B
- references/ops/cli-conventions.md10.0 KiB
- references/ops/cloud-audit-logs.md7.7 KiB
- references/ops/cloud-billing.md9.7 KiB
- references/ops/cloud-capacity.md10.1 KiB
- references/ops/cloud-certs.md11.3 KiB
- references/ops/cloud-connectivity.md9.0 KiB
- references/ops/cloud-iam.md15.4 KiB
- references/ops/cloud-migration.md11.0 KiB
- references/ops/cloud-namespace-admin.md20.5 KiB
- references/ops/cloud-notifications.md2.3 KiB
- references/ops/cloud-ops-api.md4.8 KiB
- references/ops/cloud-saml-scim.md8.6 KiB
- references/ops/cloud-terraform.md8.2 KiB
- references/ops/recipes.md19.1 KiB
- references/ops/self-hosted-admin.md13.9 KiB
- references/ops/workflow-health.md12.8 KiB
- references/triage/authentication.md19.3 KiB
- references/triage/blob-size-limits.md6.3 KiB
- references/triage/certificates.md32.9 KiB
- references/triage/connectivity.md14.0 KiB
- references/triage/diagnostic-ladder.md18.5 KiB
- references/triage/ha-failover.md17.8 KiB
- references/triage/non-determinism.md20.7 KiB
- references/triage/performance-bottlenecks.md8.9 KiB
- references/triage/rate-limits.md16.9 KiB
- references/triage/recipes.md21.1 KiB
- references/triage/replay.md13.5 KiB
- references/triage/runtime-errors.md16.6 KiB
- references/triage/schedule-missed.md5.8 KiB
- references/triage/sdk-snippet-review.md11.9 KiB
- references/triage/worker-health.md22.4 KiB
- references/triage/workflow-stuck.md30.7 KiB
references/triage/worker-health.md
Worker Health
Diagnose worker-side failures that surface as tasks not being picked up, picked up slowly, or dropped because no worker is actually connected to the right task queue. This file scopes to the worker-polling surface — the gap between "a task is enqueued on a Task Queue" and "a Worker Process dequeues it" — and to the direct symptoms of worker saturation (task slots, sticky cache, heartbeat).
Prerequisite: layers 1–4 already succeed. If the worker cannot connect or cannot authenticate, its pollers will never register and every symptom here is secondary — rule those out via connectivity.md, certificates.md, authentication.md first.
Out of scope here:
Pending activity / pending child / pending signal inside a specific Workflow Execution → workflow-stuck.md
Non-determinism / replay errors /
WorkflowTaskFailedloops → non-determinism.mdgRPC
RESOURCE_EXHAUSTED/ server-side throttling → rate-limits.mdDNS / TCP / endpoint / TLS / auth → earlier layers
SDK-specific worker knob names and tuning targets — described here as concepts only; ground-truth for the API names lives in each SDK's worker docs, not in this skill
Table of Contents
What "no pollers" looks like
Inspecting a Task Queue with
temporal task-queue describeSchedule-to-start latency
Worker task slots
Sticky Execution and sticky cache
Worker heartbeating, restarts, and disconnects
Cloud Namespace-level poller limits
Worker log signatures
Quick routing
What "no pollers" looks like
Symptom shape: a workflow or activity has been enqueued on a Task Queue, but no Worker picks it up. The classic server-side confirmation is that temporal task-queue describe returns no recent pollers for that queue and type.
The server's view of liveness for a Worker polling a Task Queue is time-based: "The Temporal Server records each poll request time. A LastAccessTime over one minute may indicate the Worker is at capacity or has shut down. Temporal Workers are removed if 5 minutes have passed since the last poll request." So "no pollers" can mean any of:
No worker process is reaching the frontend on this Task Queue at all.
Workers reached the frontend historically but have been silent > 5 minutes, so their poller entries have aged out.
Workers are polling a different queue (name mismatch:
foovsfoo-prodvsfoowith trailing whitespace) or a different Namespace.Workers connect and authenticate, then fail before the poll loop — crash on startup, deadlock, or TLS/auth rejection silently producing a reconnect loop.
This is a discrimination problem: the triage task is to separate "no worker was ever started" from "the worker is running but pointed somewhere else" from "the worker is running but blocked." The tools below address each.
Inspecting a Task Queue with temporal task-queue describe
The authoritative worker-side view from outside the worker process is temporal task-queue describe, which reports "a list of active Workers that have recently polled a Task Queue."
Minimal invocation
temporal task-queue describe \
--task-queue YourTaskQueueWorkflow and Activity polling happen on separate queues internally; filter with --task-queue-type (workflow, activity, or nexus):
temporal task-queue describe \
--task-queue YourTaskQueue \
--task-queue-type "activity" Flag: --task-queue-type accepts workflow, activity, nexus, and defaults to reporting all types.
Statistics the describe call returns
Per the CLI docs, a describe call without --disable-stats returns the following Task Queue statistics:
ApproximateBacklogCount— approximate number of tasks backlogged. "May count expired tasks but eventually converges to the right value."ApproximateBacklogAge— approximate age of the oldest backlog task in seconds.TasksAddRate— approximate rate at which tasks are being added, averaged over the last 30 seconds.TasksDispatchRate— approximate rate at which tasks are being dispatched, averaged over the last 30 seconds.BacklogIncreaseRate— roughlyTasksAddRate − TasksDispatchRate; docs note this is "accurate for backlogs older than a few seconds" even though the component rates can be off because of sync-matched and sticky dispatch.
These statistics are the server's view of matching-service throughput; combine them with the poller list (below) to answer "is there a worker attached, and is it keeping up?"
Reading the pollers field
The textual output includes a list of Worker identities that have recently polled the queue. The identifier Temporal reports is a Worker Identity, and by default "Temporal SDKs set a Worker Identity to ${process.pid}@${os.hostname()}". A "recent" poller is one whose LastAccessTime is within 5 minutes.
Interpretation matrix:
| Observation | What it suggests |
|---|---|
| No pollers at all | No Worker reached the frontend for this queue+type within the last 5 minutes. |
Pollers present, LastAccessTime > ~1 minute, no tasks moving | Docs note this "may indicate the Worker is at capacity or has shut down." |
| Pollers present, recent, backlog still growing | Sizing or per-task-failure issue — see Schedule-to-start latency and Worker task slots below. |
| Pollers present but identities don't match the worker fleet the user expects | Worker versioning / Build ID routing — re-run with versioning-aware flags (below). |
Reachability and versioning
On the same describe call you can request reachability information, which reports whether a given Build ID can be reached by new Workflows, only by closed Workflows, or is unreachable:
temporal task-queue describe \
--task-queue YourTaskQueue \
--select-build-id "YourBuildId" \
--report-reachabilityRelevant flags for versioning discrimination:
| Flag | Purpose |
|---|---|
--select-build-id | Filter the Task Queue describe results to one or more Build IDs. |
--select-unversioned | Include the unversioned queue. |
--select-all-active | Include all "active" versions (recent polls or new tasks). |
--report-reachability | Display task reachability. Docs note "task reachability status is deprecated in favor of Drainage Status (ie. of a Drained or Draining Worker Deployment Version) and will be removed in a future release." |
--report-config | Include Task Queue rate-limit configuration. |
--legacy-mode | Fallback for servers that do not support rules-based worker versioning; "only provides pollers info." |
--disable-stats | Suppress the statistics listed above. |
If the user is running Worker Deployments, the per-version worker view is temporal worker deployment describe-version, which reports "the task queues polled by workers in this Deployment Version, or drainage information required to safely decommission workers". Adding --report-task-queue-stats reports per-task-queue stats for that version.
Worker-level describe and list
Separate from Task Queue introspection, two worker-centric CLI commands surface individual Worker instances connected to the server:
temporal worker list --namespace YourNamespace --query 'TaskQueue="YourTaskQueue"'
temporal worker describe --namespace YourNamespace --worker-instance-key YourKeyThese depend on Worker heartbeating being enabled (see Worker heartbeating below); if heartbeating is disabled, "features that provide the list of active Workers and information about those Workers to show missing or inaccurate information."
Schedule-to-start latency
The primary latency signal for "tasks are being enqueued but not picked up promptly" is the SDK's schedule-to-start metric, split by task kind:
temporal_workflow_task_schedule_to_start_latency— "the time between when a Workflow Task is scheduled (enqueued) and when it is picked up by a Worker for processing."temporal_activity_schedule_to_start_latency— "the time between when an Activity Task is scheduled (enqueued) and when it is picked up by a Worker for processing."
Both are Worker-reported SDK metrics, available as histograms (_bucket, _sum, _count). Per the Cloud worker-health guide, "This latency should be very low, close to zero. Any higher value indicates a bottleneck", with example alert thresholds of ">200ms for your p99 value" and ">100ms for your p95 value."
Causes documented for high schedule-to-start latency
The performance-bottlenecks troubleshooting page lists, for both the Workflow-Task and Activity-Task variants:
Insufficient Worker capacity. "If there aren't enough Workers or if the Workers are overloaded, they may not be able to pick up Tasks quickly enough."
Worker configuration issues. "Improperly configured Workers, such as having too few pollers or Task slots, can lead to increased latency."
Network latency. "Workers in a different region from the Temporal cluster, or large payload size, can introduce additional latency."
Activity-specific: Task Queue configuration. "Setting
TaskQueueActivitiesPerSecondtoo low can limit the rate at which Activities are started, leading to increased Schedule-to-start latency." This is client/worker-imposed throttling, not server throttling — the symptom is latency, notRESOURCE_EXHAUSTED. The discrimination against server-side throttling is covered in rate-limits.md → Server throttled me vs. client throttled itself.Workflow-specific: High Workflow lock latency. "If many updates are made to a single execution, this can cause Workflow lock latency, which in turn affects the Schedule-to-start latency. Reduce the rate of Signals."
Cloud-side counterparts
On Cloud, two server-visible metric families let you cross-check without pulling SDK metrics:
temporal_cloud_v1_approximate_backlog_count— "Approximate number of tasks pending in a task queue. Started Activities are not included in the count as they have been dequeued from the task queue."No direct Cloud-side "no poller" metric exists. Use
temporal_cloud_v1_approximate_backlog_countrising while poll success rate is zero as the proxy signal for the "no poller" case in What "no pollers" looks like. The self-hosted equivalent isno_poller_tasks.Sync-match ratio:
temporal_cloud_v1_poll_success_sync_count / temporal_cloud_v1_poll_success_count. The Cloud worker-health page targets ">95%, but preferably >99%"; a drop indicates workers are not on hand to sync-match new tasks.
See Cloud Namespace-level poller limits for the related greedy-worker signal (poll timeouts).
Worker task slots
A Worker Entity has a bounded number of concurrent Task execution slots per task kind. When those slots saturate, even a well-connected Worker stops picking up new Tasks, and the symptom is identical to "too few Workers": rising schedule-to-start latency.
The worker-side gauge is temporal_worker_task_slots_available: "The total number of Workflow, Activity, Local Activity, or Nexus Task execution slots that are currently available. Use the worker_type key to differentiate execution slots." Cloud worker-health documents the monitoring target: "The temporal_worker_task_slots_available metric should always be >0."
Docs call out two common depletion patterns:
Workflow-Worker slot depletion — usually driven by inbound Workflow Task load exceeding the configured cap, or by elevated
temporal_workflow_task_execution_latency/workflow_task_replay_latencyholding slots longer.Activity-Worker slot depletion — docs' first-listed cause is "Blocked Activities and Zombie Activities ... when an Activity times out (hits its
StartToCloseorHeartbeatTimeouttimeout) and has stopped Heartbeating but continues to run, occupying some or all the slots as more retries occur." A companion gauge,temporal_worker_task_slots_used, surfaces how many slots are in use.
The configuration knobs that set these slot caps differ by SDK; the Cloud worker-health page refers to maxConcurrentWorkflowTaskExecutionSize and maxConcurrentActivityExecutionSize as the generic names, and the Worker tuning reference documents the per-SDK defaults (e.g., Go 1,000; Java 200; TypeScript 40 / 100; Python 100; .NET 100). For SDK-specific API names and tuning, follow /develop/worker-performance and /develop/worker-tuning-reference rather than guessing.
The triage-layer conclusion is: confirm slot availability is non-zero over the period the task was stuck; if it is chronically zero, the ceiling is the Worker, not the server.
Sticky Execution and sticky cache
Concept: "Workers cache the state of the Workflow they execute. ... Temporal employs a performance optimization known as 'Sticky Execution', which directs Workflow Tasks to the same Worker that previously processed tasks for a specific Workflow Execution." Each Worker gets an "automatically-generated" Sticky Queue name exclusive to that Worker.
Failure mode relevant to triage: if the Worker fails to start a queued Workflow Task in its Sticky Queue "shortly after it's scheduled (within five seconds by default), the Temporal Service disables stickiness for that Workflow Execution" and reschedules on the original Task Queue. A related trigger: if a Workflow Task fails, "the Worker removes that Workflow Execution from its cache ... which invalidates the Sticky Execution."
Key metrics for cache-pressure diagnosis:
temporal_sticky_cache_size— "Current cache size, expressed in number of Workflow Executions."temporal_sticky_cache_total_forced_eviction/_total— counter for forced evictions. "A 'forced eviction' ... means that a Workflow Execution was removed from the cache before it completed, typically because the cache was full and needed to make room for other Workflow Executions." Available in the Go SDK and the Java SDK.temporal_sticky_cache_hit_total/temporal_sticky_cache_miss_total— sticky match versus Event-History-replay.
The Cloud worker-health guidance: "The sticky_cache_size should report less than or equal to your WorkflowCacheSize value. Also, sticky_cache_total_forced_eviction should not be reporting high numbers (relative)." The WorkflowCacheSize / StickyWorkflowCacheSize per-SDK defaults are in the Worker tuning reference (Go 10,000; Java 600; TypeScript dynamic; Python 1,000; .NET 10,000).
Triage-layer conclusions:
A workflow that keeps moving but with elevated schedule-to-start latency and a high sync-match-miss or a high forced-eviction rate is starving the cache, not a pollers-missing problem.
A workflow that was Sticky to a Worker that later died or restarted will wait up to five seconds before the Sticky-queue scheduler gives up and the Task returns to the shared queue.
Worker heartbeating, restarts, and disconnects
Temporal Workers send a heartbeat to the Server on an interval. Per the Cloud worker-health guide (the feature is "in Public Preview" as documented): "Workers send a heartbeat to Temporal Server every 60 seconds by default. This heartbeat serves to provide liveness and configuration data from the Worker to the Server." Heartbeats feed the temporal worker list / temporal worker describe views; "Disabling the Worker heartbeat will cause features that provide the list of active Workers and information about those Workers to show missing or inaccurate information."
Heartbeating is distinct from Task Queue polling. A Worker process can stop polling (or start failing polls) for reasons that do not appear in its heartbeat. Consequently:
If
temporal task-queue describeshows no pollers buttemporal worker list --query 'TaskQueue="..."'shows recent Workers, the Workers are alive and heartbeating but not polling this queue (name mismatch, task-queue-type mismatch, or they've exhausted slots).If
temporal worker listis empty for a Namespace where the user insists workers are running, the likeliest triage question is "is heartbeating disabled?" or "do the workers predate an SDK version with heartbeating available?" Per the Cloud worker-health page, heartbeating is available in specific SDK versions: Go SDK v1.41.0+, Java SDK v1.35.0+, Python SDK v1.20.0+, TypeScript SDK v1.14.0+, .NET SDK v1.10.0+, Ruby SDK v1.1.0+.
Restart-loop / container-kill failure shapes are operating-system and orchestrator concerns, not Temporal-specific errors — the triage-layer observation is that a Worker in a restart loop will never sustain the 5-minute LastAccessTime window the server needs to keep it in the poller list. If the Worker container is crash-looping, the symptom will alternate between "pollers present briefly" and "pollers absent" at the restart cadence.
Cloud Namespace-level poller limits
Cloud caps the total pollers a Namespace can hold concurrently: "Temporal Cloud limits each Namespace to 20,000 Activity pollers and 20,000 Workflow Task pollers concurrently." Per the same section, "Each SDK offers a way to configure Workers for per-Worker maximum Activity and Workflow Task pollers. Those values do not affect the global Namespace limit." Saturating this cap is a Namespace-level policy limit — it falls under rate-limits.md in terms of gRPC surface behavior.
A related symptom is too many pollers for the load: the Poll Success Rate, computed as temporal_cloud_v1_poll_success_count / (temporal_cloud_v1_poll_success_count + temporal_cloud_v1_poll_timeout_count), falling well below the documented target of ">90% in most cases of systems with a steady load. For high volume and low latency, try to target >95%." The Cloud guide's interpretation: low poll success + low schedule-to-start latency + low Worker host utilization together suggest "you might have too many Workers."
Self-hosted has no equivalent documented Namespace-wide poller cap in this skill's primary sources; see docs/references/dynamic-configuration.mdx for per-service RPS and capacity keys and rate-limits.md → Self-hosted: service-level RPS via dynamic configuration.
Worker log signatures
Patterns to watch for in the Worker's own process logs when correlating with task-queue describe output. Each row points to the file that actually owns the diagnostic.
| Log pattern (shape — exact wording is SDK/version-specific) | Interpretation | Route |
|---|---|---|
gRPC UNAUTHENTICATED / PERMISSION_DENIED at worker startup or on poll RPCs | Identity or authorization rejected after TLS; Worker never registers as a poller | authentication.md |
x509: ... / tls: ... | TLS handshake or cert validation failed before gRPC | certificates.md |
no such host / connection refused / i/o timeout | DNS / TCP problem; poll loop never engages | connectivity.md |
gRPC RESOURCE_EXHAUSTED | Server throttling the Worker's RPCs (polls or other) | rate-limits.md |
temporal_long_request_failure elevated on PollWorkflowTaskQueue / PollActivityTaskQueue | Long-poll RPCs failing; docs note this "is often indicated by a ResourceExhausted status code" when caused by rate limiting, but also covers network issues and server errors | rate-limits.md / connectivity.md depending on the status / code tag on the metric |
"Deadlock detected during Workflow run" / TMPRL1101 | Workflow Task ran longer than the SDK's deadlock-detection threshold | non-determinism.md and the relevant SDK docs |
| Replay-divergence messages from the SDK (non-determinism) | Re-execution of recorded history no longer matches the compiled Workflow | non-determinism.md |
| Unhandled exception / panic / OOM kill at process level, no Temporal-specific error | Runtime-level failure, not a Temporal error string; the Worker will drop out of the poller list until restarted | OS / runtime tooling; not covered in this skill |
Correlate these with task-queue describe output. Agreement (log says "polling" and describe shows a fresh poller) confirms the Worker is healthy at the server's view. Disagreement is itself a diagnostic signal — e.g., log says "connected" but task-queue describe is empty → likely a Namespace or Task Queue name mismatch, or heartbeating is disabled so worker list is silent while polling still works.
Quick routing
| Symptom | Go to |
|---|---|
temporal task-queue describe returns no pollers | What "no pollers" looks like |
temporal_cloud_v1_approximate_backlog_count rising with zero poll success on Cloud | Schedule-to-start latency (proxy for no-poller on Cloud; no direct no-poller metric exists) |
Pollers are present but LastAccessTime stale | What "no pollers" looks like and Worker heartbeating |
temporal_workflow_task_schedule_to_start_latency or temporal_activity_schedule_to_start_latency spike | Schedule-to-start latency |
temporal_worker_task_slots_available hits 0 | Worker task slots |
Elevated temporal_sticky_cache_total_forced_eviction | Sticky Execution and sticky cache |
temporal worker list is empty but workers are running | Worker heartbeating |
| Low Poll Success Rate with low schedule-to-start latency and low host utilization | Cloud Namespace-level poller limits — likely too many Workers |
RESOURCE_EXHAUSTED on poll RPCs | rate-limits.md |
| Workflow Execution is stuck with a pending activity / child / signal | workflow-stuck.md |
| Replay errors / non-determinism in Worker logs | non-determinism.md |
See the whole-stack picture in diagnostic-ladder.md.
Requirements and compatibility
Written for: OpenAI Codex, Claude Code
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Claude Code frontmatter, Needs an API key
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Temporal
- Publisher
- OpenAI (Official)
- Distributed by
- OpenAI
- Source
- openai/plugins · plugins/temporal/skills/temporal-ops · commit d420d13
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from plugins/temporal/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Temporal or OpenAI.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download temporal-ops.zip