Repository navigation
feat: standalone activities and cross-queue executeActivity - #471
Conversation
Client: ContractClient.startActivity / executeActivity / getActivityHandle
run a contract's global activity with no workflow (Temporal Server 1.32+),
on the contract's task queue, with input/output validation and declared
errors rehydrated into ContractError.
Worker: context.executeActivity(contract, name, { args, ...options })
calls another contract's activity from a workflow; the task queue comes
from the target contract, so it is written once, on the contract whose
worker polls it.
Activity bound predicates move to @temporal-contract/contract/internal so
client and worker share one copy.
Closes #467
Refs #452
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 40 minutes. View limit details
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 18232af181
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🔵 Needs a closer look
It introduces a large new public API surface spanning client, worker, and contract packages and depends on Temporal's newer standalone-activity API that cannot be fully verified here, warranting human review.
1 open finding
What changed in this PR
This PR adds typed standalone activity execution on two surfaces, closing #467 and answering #452. It lets a client run a contract's global activity directly (no workflow) via ContractClient.startActivity / executeActivity / getActivityHandle (Temporal Server ≥ 1.32), and lets a workflow run another contract's global activity on that contract's own task queue via context.executeActivity(contract, name, { args }). Both reuse the existing validate-on-send / parse-on-receive wrapper and contract-error rehydration, so routing a rate-limited/dedicated-pool activity no longer requires a duplicated activityOptionsByName taskQueue entry per calling workflow. The activity-bound predicates move to @temporal-contract/contract/internal so client and worker enforce the same per-attempt/total bound rules.
Changes:
- Client: new
activity.ts(typed handle +startActivity), seven new error classes/tags, three pattern groups, option/type additions, andContractClientmethods. - Worker:
context.executeActivitybuilt from a shared, bound-checked, option-merging wrapper on the target contract's queue. - Contract: extracted
activity-bounds.ts(structural, Temporal-free) re-exported as_internal_*; docs, changesets, and E2E/typing tests.
| File | Description |
|---|---|
| packages/contract/src/activity-bounds.ts | New shared, structural bound predicates (per-attempt/total). |
| packages/contract/src/internal.ts | Re-exports bound predicates under _internal_ prefix. |
| packages/worker/src/activity-bounds.ts | Now re-exports the shared predicates; keeps BoundViolation/messages. |
| packages/worker/src/activities-proxy.ts | Adds createExecuteActivity, ContractActivityOf, TypedExecuteActivityOptions. |
| packages/worker/src/workflow.ts | Wires executeActivity into WorkflowContext with docs/types. |
| packages/worker/src/middleware.ts | Documents absent workflowExecution for standalone calls. |
| packages/worker/src/{execute-activity,types-inference,tests/routing*}.spec/contract/workflows | Unit + E2E routing coverage for executeActivity. |
| packages/client/src/activity.ts | New typed activity handle, start/classify logic. |
| packages/client/src/{errors,error-tags,error-patterns}.ts | New activity error classes, tags, and pattern groups. |
| packages/client/src/{types,options,internal,client,index,handle}.ts | Types/options, lookupActivity, generalized rehydrateFailedResult, public API. |
| packages/client/src/__tests__/standalone-activity.spec.ts + types-inference.spec.ts | E2E (CLI dev server) + typing coverage. |
| packages/{client/package.json, ...}, pnpm-lock.yaml | Adds @temporalio/testing client devDependency. |
| packages/testing/src/test-rig.spec.ts | Marks new standalone methods as non-start. |
| docs/**, EXAMPLES.md, .changeset/* | New how-to, reference updates, routing pointers, changesets. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- getActivityHandle takes runId in a trailing options bag, like getHandle - re-export TypedExecuteActivityOptions from @temporal-contract/worker/workflow - pin the ACTIVITY_* pattern groups in error-patterns.spec.ts Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9be5cd0f74
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Under idConflictPolicy "USE_EXISTING", Temporal returns whichever running execution holds the activity ID. Describe it and report a type or queue mismatch as ActivityAlreadyStartedError instead of typing an unrelated execution with this activity's schemas. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d773587e9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Closes #467. Refs #452.
Client: standalone activities
ContractClient.startActivity/executeActivity/getActivityHandlerun a contract's global activity with no workflow around it (Temporal Server 1.32+).argsis validated before start; the result is parsed against the output schema.TypedActivityHandle.result()rehydrates the activity's declared errors intoContractError, and maps cancelled / terminated / timed-out executions toActivityCancelledError/ActivityTerminatedError/ActivityTimeoutError. Other failures areActivityFailedError.describe/cancel/terminatereturnActivityExecutionNotFoundErrorfor an unknown ID.ACTIVITY_START_PATTERNS,ACTIVITY_RESULT_PATTERNS,ACTIVITY_EXECUTE_PATTERNS.activityOptionsare the defaults; call options shallow-merge over them. The merged options must have a per-attempt and a total bound, or the call is a defect.Worker:
context.executeActivity(related to #452)This is the alternative floated in the maintainer's comment on #452 (routing comes from the activity-only contract that hosts the activity). It does not implement #452's ask,
taskQueueinContractActivityOptions, and #452 is waiting on the reporter's feedback, so this PR doesn't close it.executeChildWorkflow: the queue comes from the target contract, so it's written once, on the contract whose worker polls it.context.activities.X.activityOptions< activity's contractactivityOptions< per-call.taskQueueis not accepted.Other changes
@temporal-contract/contract/internal, shared by client and worker.run-activities-on-a-dedicated-queue, client/worker reference updates, routing pointer intune-activity-options, middleware note that a standalone call has noworkflowExecution.EXAMPLES.mdmarks standalone activities ✅.Testing
execute-activity.spec.ts(worker), typing tests in both packages'types-inference.spec.ts.routing.spec.tsregisters the activity only on the activity-only contract's worker, so the workflow completes only if routing works.standalone-activity.spec.tsusesTestWorkflowEnvironment.createLocal()(CLI dev server, Temporal 1.32.0), because the testcontainersauto-setupimage stops at 1.29. Adds@temporalio/testingas a client devDependency.Not included
client.activity.list/countaren't wrapped; useraw.🤖 Generated with Claude Code
Summary by CodeRabbit
executeActivity. Activity options are combined across workflow, contract, and call settings; per-attempt and total time bounds are required.