diff --git a/AUTHORING_LOG.md b/AUTHORING_LOG.md new file mode 100644 index 0000000..94bce3f --- /dev/null +++ b/AUTHORING_LOG.md @@ -0,0 +1,56 @@ +# Authoring Log + +## Standalone Activities feature (added per `STANDALONE_ACTIVITIES_AUTHORING_PLAN.md`) + +Six new reference files plus a surgical `SKILL.md` edit. Each reference file was authored by an isolated subagent that read only the docs paths assigned to it (no cross-reading of sibling reference files). + +### `references/core/standalone-activities.md` +- **Docs consulted:** `docs/encyclopedia/activities/standalone-activity.mdx` (primary), `docs/cloud/metrics/openmetrics/metrics-reference.mdx` (line 315, for the no-new-metric-names claim). Supporting files (`activities.mdx`, `activity-execution.mdx`, `job-queue.mdx`) referenced by link only. +- **Citations:** 26 inline. +- **VERIFY markers:** 0. +- Self-checks passed: `TerminateExisting` / `TerminateIfRunning` listed only as unsupported; pause/reset/update-options listed only as unsupported; CLI v1.7.0+ / Server v1.31.0+ stated verbatim; separate ID space; dual-use claim preserved verbatim; no invented metric names; no TypeScript link. + +### `references/core/standalone-activities-cli.md` +- **Docs consulted:** `docs/cli/activity.mdx` (full file), `docs/encyclopedia/activities/standalone-activity.mdx` (lines 23, 109–114, 135–138). +- **Citations:** 50 inline. 323 lines. +- **VERIFY markers:** 0. +- All 14 `temporal activity` subcommands have their own H3 headings. Public Preview gaps (`pause`, `reset`, `update-options`) flagged at top and at each subcommand. `unpause` annotated since it only operates on paused Activities, which Standalone Activities cannot enter in Public Preview. Global Flags referenced by line range, not transcribed. + +### `references/python/standalone-activities.md` +- **Docs consulted:** `docs/develop/python/activities/standalone-activities.mdx` only. +- **Citations:** 30 inline. +- **VERIFY markers:** 2. + 1. Server v1.31.0+ requirement is not stated in the Python doc (only CLI v1.7.0+ and Python SDK v1.23.0+ are stated there). The encyclopedia is the source for the server-version pairing. + 2. The Python doc does not show conflict-policy / reuse-policy kwargs on `start_activity` (`USE_EXISTING`, `REJECT_DUPLICATES`, etc.). Per methodology, no kwargs were invented; policy semantics deferred to `references/core/standalone-activities.md`. +- Methods/kwargs used: `client.execute_activity`, `client.start_activity`, `client.get_activity_handle`, `activity_handle.result`, `client.list_activities`, `client.count_activities`, `ClientConfig.load_client_connect_config`. Cloud auth limited to mTLS + API key (env-var modes). + +### `references/go/standalone-activities.md` +- **Docs consulted:** `docs/develop/go/activities/standalone-activities.mdx` (primary), `docs/encyclopedia/activities/standalone-activity.mdx` (versions + Public Preview limitations only). +- **Citations:** 33 inline. ~270 lines. +- **VERIFY markers:** 1. The Go doc does not show the exact field name on `StartActivityOptions` for conflict policy / reuse policy, nor the Go enum constants for `USE_EXISTING` / `REJECT_DUPLICATES`. The encyclopedia lists the policy values but Go-specific binding names need confirmation against the godoc before adding a code snippet. +- APIs verbatim from the Go doc: `ExecuteActivity`, `GetActivityHandle`, `ListActivities`, `CountActivities`, `StartActivityOptions`, `GetActivityHandleOptions`, `ListActivitiesOptions`, `CountActivitiesOptions`, handle methods `Get`/`GetID`/`GetRunID`. + +### `references/java/standalone-activities.md` +- **Docs consulted:** `docs/develop/java/activities/standalone-activities.mdx` (primary), `docs/encyclopedia/activities/standalone-activity.mdx` (versions + Public Preview limitations only). +- **Citations:** 33 inline (32 to the Java doc, 4 to the encyclopedia — some overlap). +- **VERIFY markers:** 1. The Java doc does not show builder methods on `StartActivityOptions` for conflict policy / reuse policy. Policy values documented as concepts; Java setter names not invented. +- Prereqs documented: Java 8+, Java SDK v1.35.0+, CLI v1.7.0+, Server v1.31.0+. Cloud auth limited to mTLS and API key. + +### `references/dotnet/standalone-activities.md` +- **Docs consulted:** `docs/develop/dotnet/activities/standalone-activities.mdx` (primary), `docs/encyclopedia/activities/standalone-activity.mdx` (versions + Public Preview limitations only). +- **Citations:** 32 inline (28 to the .NET doc, 4 to the encyclopedia). +- **VERIFY markers:** 1. The .NET doc does not show a code snippet wiring `USE_EXISTING` / `REJECT_DUPLICATES` into `StartActivityOptions`; the specific .NET option property names are not present. Documented the supported policy values (from the encyclopedia) and the unsupported `TerminateExisting` / `TerminateIfRunning` limitation, without inventing .NET property names. +- APIs verbatim from the .NET doc: `ExecuteActivityAsync`, `StartActivityAsync`, `GetActivityHandle`, `GetResultAsync`, `ListActivitiesAsync`, `CountActivitiesAsync`, `StartActivityOptions`, `[Activity]`, `TemporalWorker`, `TemporalWorkerOptions`, `AddActivity`, `ClientEnvConfig.LoadClientConnectOptions`, `ActivityExecution`. Cloud auth limited to mTLS and API key. + +### `SKILL.md` edit +- Added a "Standalone Activities" section just above "Task Queue Priority and Fairness", pointing at the six new reference files and noting that TypeScript SDK coverage is upstream-pending. +- No other changes to existing sections; skill version field left at `0.3.2` (no user request to bump). + +### Cross-cutting VERIFY summary + +The five language/CLI subagents converged on a single shared gap: **the per-language docs do not yet show conflict-policy / reuse-policy parameter wiring** (Python kwargs, Go fields, Java builders, .NET options). The encyclopedia lists the policy values (`USE_EXISTING`, `REJECT_DUPLICATES`; with `TerminateExisting` / `TerminateIfRunning` unsupported in Public Preview). Recommended follow-up: when the SDK docs add policy snippets (or when the API surface is confirmed against the per-language godoc/javadoc/etc.), revisit the four language references and resolve the VERIFY markers. + +### Files NOT modified + +- `references/typescript/` — intentionally untouched. No upstream Standalone Activities doc exists. +- `references/python/advanced-features.md`, `references/go/advanced-features.md`, etc. — left as-is. The plan reserved the option to add a one-line cross-link, but the SKILL.md "Standalone Activities" section already provides the discovery path; no edit was needed. diff --git a/SKILL.md b/SKILL.md index ff770cd..1b6d7bb 100644 --- a/SKILL.md +++ b/SKILL.md @@ -77,6 +77,21 @@ Check if `temporal` CLI is installed. If not, follow the instructions at `refere - **`references/core/ai-patterns.md`** - AI/LLM pattern concepts - Language-specific info at `references/{your_language}/ai-patterns.md`, if available. Currently Python only. +## Standalone Activities + +Standalone Activities are Temporal's [Public Preview](https://docs.temporal.io/evaluate/development-production-features/release-stages#public-preview) job-queue primitive: a single Activity executed directly by a Client as a top-level execution, without a Workflow. Use them when you only need to run **one** Activity reliably (send an email, process a webhook, sync data, etc.) — for orchestrating multiple Activities, use a Workflow. The same Activity Function runs as a Standalone Activity or a Workflow Activity with no code changes. + +Requires Temporal CLI v1.7.0+ and Temporal Server v1.31.0+. Public Preview in Temporal Cloud. + +- **`references/core/standalone-activities.md`** — concept, when-to-use, dual-use with Workflows, conflict/reuse policies, Public Preview limitations, observability, Cloud support +- **`references/core/standalone-activities-cli.md`** — `temporal activity` CLI subcommand reference (`start`, `execute`, `result`, `list`, `count`, `describe`, `cancel`, `terminate`, etc.) +- Per-language quickstarts and APIs: + - **`references/python/standalone-activities.md`** + - **`references/go/standalone-activities.md`** + - **`references/java/standalone-activities.md`** + - **`references/dotnet/standalone-activities.md`** + - TypeScript SDK: not yet covered upstream — point users at the Python or Go reference for now. + ## Task Queue Priority and Fairness If the developer is building a **multi-tenant application**, proactively recommend Task Queue Fairness. Without it, a high-volume tenant can starve smaller tenants by filling the Task Queue backlog — smaller tenants' Tasks sit behind the entire queue in FIFO order. Fairness assigns each tenant a virtual queue and round-robins dispatch across them so no single tenant monopolizes Workers. diff --git a/SKILL_AUTHORING_PLAN_TEMPLATE.md b/SKILL_AUTHORING_PLAN_TEMPLATE.md new file mode 100644 index 0000000..03eccaa --- /dev/null +++ b/SKILL_AUTHORING_PLAN_TEMPLATE.md @@ -0,0 +1,309 @@ +# Skill Authoring Plan — `{{SKILL_NAME}}` + +**Reader:** you are an AI agent. The user has told you to write a Temporal skill using this template. Your job has two phases: + +1. **Phase 1 — Fill this plan.** Search the documentation clone, fill every `{{PLACEHOLDER}}`, resolve every `[CHOOSE: …]` fork, and delete any section marked optional that doesn't apply. Present the filled plan to the user for approval before proceeding. +2. **Phase 2 — Execute the filled plan.** Follow the plan you just produced to author the skill. + +Do not start Phase 2 until the user approves the filled plan. + +--- + +## How to fill the placeholders (Phase 1 instructions) + +Work through these steps in order. Each step tells you how to derive the values for one or more placeholders below. + +### Step A: Identify the topic + +The user will name the topic (e.g. "nexus", "schedules", "operations"). If they haven't, ask. Record it as `{{SKILL_NAME}}`. The skill directory you're working in is `{{SKILL_ROOT}}`. + +### Step B: Discover docs paths for §1 + +Search the local docs clone: + +1. `find ../documentation/docs/ -iname "**"` — find primary files. +2. Grep for the topic keyword across `docs/` — find secondary mentions. +3. Read the primary files to understand scope, subcommands, flags, enums, concepts. +4. Check `../` for sibling clones that might serve as secondary sources. + +Fill the `docs/{{PATH}}` entries in §1 with specific file paths. Be specific — `docs/cli/workflow.mdx` not `docs/cli/`. + +### Step C: Decide mode and fill §2 + +If a prior skill exists in this directory with files to rewrite, mode = **rewrite**. Read the existing files, identify what scaffolding is sound (section structure, framing, decision tables) vs. what body facts are untrusted. Fill §2. + +If no prior skill exists, mode = **greenfield**. Delete §2 entirely. + +### Step D: Fill the grep-first example in §3.1 + +Pick one concrete factual question from this topic (e.g. "what flags does `temporal schedule create` take?"). Fill `{{EXAMPLE_QUESTION}}`, `{{EXAMPLE_PATH}}`, `{{EXAMPLE_SECTION}}`, and `{{EXAMPLE_CLAIM}}` in §3.1 and §3.2. + +### Step E: Decide on source-category tagging in §3.2 + +If the topic spans sources beyond the Temporal docs (Go stdlib, gRPC spec, tool man pages), uncomment the optional source-category tagging subsection. If it lives entirely within Temporal docs, delete it. + +### Step F: Fill topic-specific anti-fabrication rules in §3.4 + +Read the docs files you found. For each category of factual token, note patterns an AI is likely to get wrong. Write concrete rules. If this is greenfield and you can't yet identify traps, write your best guesses and note that §8 will grow during validation. + +### Step G: Design the reference-file layout for §5 + +Based on docs structure, decide how to decompose the skill into reference files under `references/`. Follow sibling skill conventions — check `../skill-temporal-cli/` and `../skill-temporal-triage/` for the standard layout (SKILL.md at root, reference files under `references/` or `references/core/`). Match the SKILL.md frontmatter schema. + +Order files so shared concepts come first, recipes/playbooks last, SKILL.md always last. Fill §5. + +### Step H: Build §8 regression table and §9 anchors + +- **Regression table (§8):** For rewrite mode, review existing files and cross-check against docs — every wrong pattern goes in the table. For greenfield, the table may start empty. +- **Anchors (§9):** Pick 5–15 verified facts from the docs with line numbers. + +### Step I: Check for sibling handoff + +`ls ../skill-temporal-*/`. If the topic touches concepts in a sibling skill, uncomment the optional §11 and fill the handoff rules. + +--- + + + +**Mode:** [CHOOSE: greenfield | rewrite] + +**Context:** {{ONE-PARAGRAPH CONTEXT. For greenfield: why this skill, what topic, what audience, what sibling skills exist. For rewrite: the existing skill was AI-generated without grounding and contains factual errors; your job is a grounded rewrite of the body, preserving scaffolding where it's sound.}} + +--- + +## 1. Source of truth + +**Primary (authoritative):** the local clone of `temporalio/documentation` at `../documentation/`. + +Relevant paths for `{{SKILL_NAME}}`: + +- `docs/{{PATH_1}}` — {{ONE-LINE DESCRIPTION}}. +- `docs/{{PATH_2}}` — {{…}}. +- `docs/{{PATH_3}}` — {{…}}. + +**Secondary (only if primary is silent):** {{LIST UPSTREAM SOURCES IF ANY. Omit if topic lives entirely in `documentation/`.}} + +Prefer Read/Grep on a local clone over WebFetch or `gh api`. Check `../` for sibling clones before reaching for the network. + +**Never trust:** {{FOR REWRITE: the existing files for factual claims — treat as outline only. FOR GREENFIELD: any prior sketches or wiki pages — treat as inputs to the Intent table, not as ground truth.}} + +--- + +## 2. Preserve vs. rewrite + + + +### Preserve (conceptual scaffolding that was good) + +- {{BULLET each piece of structure worth keeping.}} + +### Rewrite (treat as untrusted) + +- Every command string, flag name, flag value, enum, env var, endpoint, port, file path, and example in every reference file. +- {{ADD topic-specific items that are known-untrusted.}} + +--- + +## 3. Methodology — the verification protocol + +Follow this protocol for **every** factual claim you write. No exceptions. + +### 3.1 The grep-first rule + +Before writing a flag name, command, enum, error string, env var, or API shape, open the relevant docs file and confirm it is present verbatim. Use Grep with the exact token. Do **not** paraphrase from memory — memory is what produces fabrications. + +Example workflow for "{{EXAMPLE_QUESTION}}": + +1. `Read ../documentation/docs/{{EXAMPLE_PATH}}` §{{EXAMPLE_SECTION}}. +2. Transcribe only what appears in that file. +3. Record the line number where you found it. + +### 3.2 Citation/provenance format + +Every reference file must carry inline provenance. Use HTML comments so the rendered page stays clean: + +```markdown +`{{EXAMPLE_CLAIM}}` +``` + +Pick one convention (inline comment per claim *or* `` footer per section) and use it consistently. Keep citations to local repo paths (no URLs). + + +`{{GO_CLAIM}}` +`{{GRPC_CLAIM}}` +`{{TOOL_CLAIM}}` +``` + +This is defensive: it surfaces when a claim is sourced from the wrong place. +end optional --> + +### 3.3 Anti-fabrication rules (generic) + +Refuse each of these patterns explicitly: + +1. **No "probably exists" commands/subcommands.** If it's not in the docs, it doesn't exist. +2. **No "probably accepts" enum values.** Only list enum values present in the docs. +3. **No "probably named" env vars, flags, or fields.** Transcribe from the authoritative table. +4. **No inferred flag names.** Don't derive `TEMPORAL_{{X}}_{{Y}}_PATH` from `--{{x}}-{{y}}-path`. Name-shape plausibility is not evidence. +5. **No conflating concept with interface.** Platform concepts and CLI/SDK tokens often have subtly different names. Document the interface token; name the concept separately with a pointer. +6. **No flattening of subcommand groups.** If the docs show a group with N subcommands, don't flatten to one command with a flag. +7. **No assumed defaults.** Don't write "default: X" unless the docs say so. + +### 3.4 Anti-fabrication rules (topic-specific) + +- {{TOPIC-SPECIFIC TRAP 1}} +- {{TOPIC-SPECIFIC TRAP 2}} +- {{TOPIC-SPECIFIC TRAP 3}} + +### 3.5 When the docs are ambiguous or silent + +Options in order of preference: + +1. Check a secondary authoritative source (upstream repo README, generator source file like `commands.yml`, SDK source). +2. Note the ambiguity in a `` comment and leave the claim out of the prose. +3. Do **not** guess. Do **not** synthesize from "this is how it probably works." + +Never fabricate to fill a gap. An empty section with a VERIFY note is acceptable; a fabricated section is not. + +### 3.6 Stay descriptive, not prescriptive-beyond-docs + +Where the docs describe what a thing does, you describe what that thing does. Where the docs don't prescribe a workflow, don't invent one. Recipes/playbooks are the one exception — they chain documented facts — and each step must cite the doc where the fact comes from. + +--- + +## 4. Execution + +Use an **orchestrator + per-file subagent** shape. + +### Step 1: Read this plan end-to-end + +Do not start editing until you've read all sections, especially §8 (regression patterns) and §9 (known correct anchors). + +### Step 2: Set up the workspace + +For rewrite: work directly in `{{SKILL_ROOT}}`. +For greenfield: create the skill directory layout (`SKILL.md`, `references/` with files per §5). + +### Step 3: Author each reference file via a subagent + +For each file in §5 (in order), spawn a subagent. Give the subagent: + +- **The single file it owns.** One file per subagent — no cross-reading of sibling reference files. +- **The docs paths** from §1 that are relevant to that file (listed in §5). +- **The full methodology** from §3 (grep-first rule, citation format, all anti-fabrication rules). +- **The regression patterns** from §8 — self-check against these before committing. +- **Instructions:** "You are writing `FILE_NAME`. Read ONLY the docs paths listed. Do NOT read sibling reference files. Produce one commit. Report: citation count, docs files consulted, `` markers raised." + +### Step 4: Author SKILL.md + +After all reference-file subagents complete, write `SKILL.md` yourself (the orchestrator). Update the Intent table and framing to reflect verified content. + +### Step 5: Produce the log + +Compose `AUTHORING_LOG.md` from subagent reports: for each reference file, docs files consulted, citation count, `` markers. + +### What NOT to do + +- Do not read or reference any prior conversation or previous version of the skill beyond what §2 tells you to keep. +- Do not read the paired validation plan. +- Do not create files outside `references/` and the skill root. + +--- + +## 5. Per-file execution order + +Work in this order. Each file's correctness depends on the files above it — shared concepts established early are inherited by later files. + +1. **`references/{{FILE_1}}.md`** — {{ONE-LINE TOPIC}}. Ground truth: `docs/{{PATH}}`. +2. **`references/{{FILE_2}}.md`** — {{…}}. Ground truth: `docs/{{PATH}}`. +3. **`references/{{FILE_3}}.md`** — {{…}}. Ground truth: `docs/{{PATH}}`. +4. {{…}} +5. **`references/{{RECIPES_FILE}}.md`** — end-to-end flows. Each step must already be grounded in earlier files; copy citations forward. +6. **`SKILL.md`** — **last**. Update the Intent decision table / top-level framing to reflect verified content; update install/setup commands from their canonical docs file. + +Why this order matters: {{ONE OR TWO SENTENCES ON THE DEPENDENCY GRAPH.}} + +--- + +## 6. Per-file done criteria + +A reference file is done when: + +1. Every command string, field name, error string, or API shape appears verbatim in the docs (or has a `` marker with a specific question). +2. Every name/token has a citation comment. +3. Every enum value is traceable to a docs file. +4. No subcommand / field / enum appears that isn't in the relevant `docs/` file's headings or tables. +5. A self-check Grep finds zero instances of the regression patterns listed in §8. + +--- + +## 7. Deliverables + +At the end of authoring, produce: + +- **`AUTHORING_LOG.md`** at the skill root: for each reference file, docs files consulted, total citation count, `` markers with questions and sources of ambiguity. +- **A git-visible diff** — one commit per reference file, so review can proceed file-by-file. + +Do not create files outside `references/` and the skill root. No `docs/` subdirectories, tutorials, `CONTRIBUTING.md`, or meta-docs. + +--- + +## 8. Regression patterns + +| Wrong pattern | Should be | Source | +|---|---|---| +| {{WRONG_PATTERN_1}} | {{CORRECT_FORM}} | docs/{{PATH}}:{{LINE}} | +| {{WRONG_PATTERN_2}} | {{CORRECT_FORM}} | docs/{{PATH}}:{{LINE}} | + +This table is the input to the validation plan's Check 3 (regression). Keep it in sync. + +--- + +## 9. Known correct anchors + +- {{FACT_1}} (`docs/{{PATH}}:{{LINE}}`). +- {{FACT_2}} (`docs/{{PATH}}:{{LINE}}`). +- {{FACT_3}} (`docs/{{PATH}}:{{LINE}}`). + +--- + +## 10. Non-goals + +- **Do not re-architect the skill.** Keep the file layout, section order, and `SKILL.md` frontmatter schema as dictated by this plan. +- **Do not expand scope.** The Out-of-scope section defines what belongs in sibling skills. Don't pull those topics in. +- **Do not paraphrase docs prose verbatim.** The skill's value is synthesis and framing, not re-publication. Cite, don't copy. +- **Do not write tests, CI, or tooling.** This is documentation work. +- **Do not add meta-docs** (`CHANGELOG.md`, `CONTRIBUTING.md`, `ROADMAP.md`) unless the user asks. + + + +--- + +## 12. If you get stuck + +- If a fact has no docs backing, delete it or mark it ``. An absent claim is safer than a wrong one. +- If a whole section has no docs backing, delete the section and note it in `AUTHORING_LOG.md`. +- If the docs contradict this plan (plan was written from a point-in-time review and docs may have moved), trust the docs and flag the conflict in `AUTHORING_LOG.md`. + +End of plan. diff --git a/SKILL_VALIDATION_PLAN_TEMPLATE.md b/SKILL_VALIDATION_PLAN_TEMPLATE.md new file mode 100644 index 0000000..0d17b5a --- /dev/null +++ b/SKILL_VALIDATION_PLAN_TEMPLATE.md @@ -0,0 +1,212 @@ +# Skill Validation Plan — `{{SKILL_NAME}}` + +**Reader:** you are an AI agent. The user has told you to validate a Temporal skill using this template. Your job has two phases: + +1. **Phase 1 — Fill this plan.** Examine the authored skill files, identify the docs paths and token classes, fill every `{{PLACEHOLDER}}`, and present the filled plan to the user for approval. +2. **Phase 2 — Execute the filled plan.** Run the four-check protocol and produce a go/no-go report. + +**Critical constraint:** you must be a *different session* than the one that authored the skill. Do not read the authoring plan, the `AUTHORING_LOG.md`, or any prior conversation about the authoring. You validate from the authored files and the docs alone. + +Do not start Phase 2 until the user approves the filled plan. + +--- + +## How to fill the placeholders (Phase 1 instructions) + +### Step A: Identify what you're validating + +The user will point you at a skill directory. Record the path as `{{SKILL_ROOT}}`. Read `SKILL.md` to understand the topic and scope. List all reference files under `references/`. Record the topic as `{{SKILL_NAME}}`. + +### Step B: Discover docs paths for §2 + +From the authored files, extract the docs paths cited in `` comments. Confirm these files exist under `../documentation/docs/`. Fill the path entries in §2. + +If the skill cites non-docs sources (``, ``, ``), note those as secondary sources in §2. + +### Step C: Build token-extraction patterns for Check 2 + +Scan the authored files and categorize which classes of factual tokens appear. Fill the patterns in Check 2. Typical classes: + +- Flag names: `--[a-z][a-z0-9-]+` +- Command invocations: `^\s*(temporal|tcld) ` inside code fences +- Env vars: `TEMPORAL_[A-Z_]+` +- Enum values quoted in tables +- Error strings (for triage-style skills) +- API fields / types (topic-dependent) + +### Step D: Build the regression table for Check 3 + +Start with the universal regression patterns already in Check 3 below. Then check whether the skill directory contains an `AUTHORING_PLAN.md` with a §8 regression table. If it does, add those entries. If no topic-specific regressions exist, the universal patterns still apply. + +If the skill covers ecosystem claims, uncomment the optional ecosystem-regression subsection. + +--- + + + +**Purpose:** independent verification that the skill is accurate, grounded, and free of fabrication patterns. Produce a go/no-go. + +**Non-purpose:** editing the skill. If validation finds problems, report them — do *not* fix them. Fixing belongs to another authoring pass. + +--- + +## 1. Independence requirement + +Validation must be performed by a different session than authoring. Do *not* reuse the orchestrator that ran the authoring subagents — it carries authoring's mental model and will miss fabrications it introduced. + +The validator agents read the *authored* files and the *docs clone*; they do **not** read the authoring plan, the `AUTHORING_LOG.md`, or any prior conversation. + +--- + +## 2. Source of truth + +- Primary: `../documentation/docs/`, with topic-relevant subtrees: + - `docs/{{PATH_1}}` + - `docs/{{PATH_2}}` + - `docs/{{PATH_3}}` +- Secondary: {{LIST IF APPLICABLE, e.g. Go stdlib, gRPC spec. Omit if not applicable.}} + +Do not trust citations in the authored files as proof — follow them and confirm the cited text supports the claim. Citations can be wrong in three ways: wrong file, wrong line, or correct line with a claim subtly different from what the line actually says. All three must be caught. + +--- + +## 3. Four-check validation protocol + +Run all four checks. The skill passes only if all four pass. + +### Check 1: citation audit + +Mechanical. For every inline citation comment in the authored files: + +1. Confirm the cited file exists under `../documentation/docs/` (or the secondary-source location, for ecosystem tags). +2. Read the cited line range. +3. Confirm the authored claim is substantively supported by the cited text — not merely adjacent to it. + +**Pass criterion:** ≥ 98% of citations resolve cleanly. Any unresolved citation is a finding. + +**How to run:** Grep the authored files for ``. +- The token is an ecosystem token — acceptable only if tagged with its source category. + +**Pass criterion:** zero unexplained grep-misses. + +### Check 3: regression on known bugs + +Any of these patterns appearing in the authored files is a failure. + +**Universal patterns (apply to every Temporal skill):** + +| Wrong pattern | Should be | +|---|---| +| `--profile` as a flag in `temporal` command | `--env` | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` | `TEMPORAL_TLS_CERT` | +| `TEMPORAL_TLS_CLIENT_KEY_PATH` | `TEMPORAL_TLS_KEY` | +| `TEMPORAL_TLS_SERVER_CA_CERT_PATH` | `TEMPORAL_TLS_CA` | +| `tcld service-account` (entire command group) | does not exist — should be absent | +| `--output text` / `--output jsonl` | `table, json, card` only | +| `saas-api.tmprl.cloud:7233` | port 443 | + +**Topic-specific patterns:** + +| Wrong pattern | Should be | Source | +|---|---|---| +| {{WRONG_PATTERN_1}} | {{CORRECT_FORM}} | docs/{{PATH}}:{{LINE}} | +| {{WRONG_PATTERN_2}} | {{CORRECT_FORM}} | docs/{{PATH}}:{{LINE}} | + +`, ``, or `` tag). +end optional --> + +**Pass criterion:** zero hits against any regression pattern. Strict — these are bugs already identified and should not survive a grounded authoring pass. + +### Check 4: independent re-verification (sampling) + +The first three checks catch fabrication and drift. This one catches *subtle-wrong*: a citation points at a real line, but the author's interpretation of that line is off by a nuance. + +Pick **10 claims at random** per reference file (typically 20–120 per skill total). For each: + +1. Read *only* the claim in the authored file — not the citation. +2. Open the cited doc *independently* and read the section fresh. +3. Write down what you think the correct claim should be, given only the docs. +4. Compare your version to the authored version. + +"Substantively different" = a reader following one would do something different than a reader following the other. Typographical / stylistic differences don't count. + +**Pass criterion:** ≥ 95% of sampled claims match. Below 95% = flag for second authoring pass. + +**How to randomize:** number all citations in a file; use a seeded approach (every Nth citation, or shuffle-by-hash) to pick. Record which citations were sampled in the report. + +--- + +## 4. Execution shape + +One validator orchestrator agent. The agent: + +1. Reads this plan. +2. Reads the authored files in `{{SKILL_ROOT}}` (not the authoring plan, not the `AUTHORING_LOG.md`). +3. Runs Check 1 — delegate to a per-reference-file subagent for parallelism. +4. Runs Check 2 — delegate per reference file. +5. Runs Check 3 — single pass across all files. +6. Runs Check 4 — delegate per reference file; each subagent reads only the docs, not the rest of the skill. +7. Produces the report per §5. + +--- + +## 5. Deliverables + +- **`VALIDATION_REPORT.md`** at `{{SKILL_ROOT}}` with sections: + - **Go/no-go** — one-line verdict per check, overall verdict. + - **Check 1 findings** — unresolved citations, with file:line and the cited-vs-actual difference. + - **Check 2 findings** — tokens not found in docs, grouped by reference file. + - **Check 3 findings** — any regression-pattern hits, file:line, the wrong text. + - **Check 4 findings** — sampled claims that diverged from docs, with both versions. + - **Statistics** — citation count, grep-miss count, sample size, match rate. +- Do *not* edit the authored files. Reports go in a separate file. + +Overall verdict rubric: + +- **GO** — all four checks pass their thresholds. +- **RE-RUN AUTHORING** — Check 3 has any hit, or Check 4 < 95%, or Check 1 < 98%. Don't patch; send affected files back through authoring. +- **MINOR FIXES** — Check 2 has ≤ 5 unexplained misses that look like typos or missing citation comments. Flag for spot-fix, no full re-authoring. + +--- + +## 6. Stop conditions + +Abort validation and escalate if: + +- The authoring output artifacts are missing (no commits, no `AUTHORING_LOG.md`) — nothing to validate. +- The docs clone at `../documentation/` is absent or empty — no source of truth. +- More than 30% of citations fail Check 1 — authoring wasn't grounded; full re-authoring needed. +- The authoring added files outside the expected skill layout (new `docs/` subdirs, tutorials, meta-docs) — flag as scope violation. + +--- + +## 7. What this plan does *not* do + +- **No live testing.** Running commands against real Temporal systems is the highest-confidence check but outside this plan's remit. +- **No prose quality grading.** Validation checks factual correctness only. +- **No scope auditing.** Whether a claim belongs in this skill vs. a sibling is a design question answered during authoring. + +End of plan. diff --git a/STANDALONE_ACTIVITIES_AUTHORING_PLAN.md b/STANDALONE_ACTIVITIES_AUTHORING_PLAN.md new file mode 100644 index 0000000..be620c0 --- /dev/null +++ b/STANDALONE_ACTIVITIES_AUTHORING_PLAN.md @@ -0,0 +1,254 @@ +# Skill Authoring Plan — `temporal-developer: Standalone Activities feature` + +**Mode:** greenfield (additive) + +**Context:** The `temporal-developer` skill exists at `/Users/don/work/skills/skill-temporal-developer/` and is otherwise complete. This plan adds a new feature — **Standalone Activities** — into the existing skill. Standalone Activities are a Public Preview Temporal feature (CLI v1.7.0+, Server v1.31.0+) that let a Client run a single Activity as a top-level execution without a Workflow — Temporal's "job queue" primitive. The feature is documented in the encyclopedia, the `temporal activity` CLI reference, and four language SDK pages (Python, Go, Java, .NET). TypeScript has no Standalone Activities doc yet, so the skill must not invent TypeScript content. The job is to author new reference files that slot into the existing layout (`references/core/` and `references/{lang}/`) and to extend `SKILL.md` to point at them. Everything else in the skill stays untouched. + +--- + +## 1. Source of truth + +**Primary (authoritative):** the local clone of `temporalio/documentation` at `../documentation/`. + +Relevant paths for Standalone Activities: + +- `docs/encyclopedia/activities/standalone-activity.mdx` — concept page: definition, use cases, key features, observability, Public Preview limitations, CLI/Cloud support requirements. +- `docs/cli/activity.mdx` — `temporal activity` subcommand reference: `cancel`, `complete`, `count`, `describe`, `execute`, `fail`, `list`, `pause`, `reset`, `result`, `start`, `terminate`, `unpause`, `update-options`, plus global flags. +- `docs/develop/python/activities/standalone-activities.mdx` — Python SDK quickstart and APIs (write Activity, run Worker, execute/start/get handle/wait/list/count, Cloud connect mTLS + API key). +- `docs/develop/go/activities/standalone-activities.mdx` — Go SDK quickstart and APIs. +- `docs/develop/java/activities/standalone-activities.mdx` — Java SDK quickstart and APIs. +- `docs/develop/dotnet/activities/standalone-activities.mdx` — .NET SDK quickstart and APIs. +- `docs/encyclopedia/activities/activities.mdx`, `docs/encyclopedia/activities/activity-execution.mdx`, `docs/encyclopedia/activities/activity-operations.mdx` — Activity fundamentals that Standalone Activities inherit (timeouts, retries, heartbeats, cancellation). Cite when explaining shared mechanics rather than restating. +- `docs/evaluate/development-production-features/job-queue.mdx` — framing of Standalone Activities as Temporal's job-queue primitive. +- `docs/cloud/metrics/openmetrics/metrics-reference.mdx` — Activity metrics that apply to Standalone Activities (cite for observability claims only). + +**Secondary (only if primary is silent):** SDK source/API references in sibling clones if present under `../`. Do not reach for the network unless the local clone is silent. + +Prefer Read/Grep on the local clone over WebFetch. + +**Never trust:** any prior sketches, slack threads, or wiki pages on Standalone Activities — treat as inputs to framing only, not as ground truth. In particular, do not invent a TypeScript SDK API surface — the docs clone has no TypeScript Standalone Activities page. + +--- + +## 2. Preserve vs. rewrite + +This feature is additive. The only existing files that get modified are `SKILL.md` (add pointers to the new references) and, if relevant, `references/{python,go,java,dotnet}/advanced-features.md` (add a one-line cross-link to the new standalone-activities reference). Do **not** rewrite existing reference content. Do **not** touch `references/typescript/` for Standalone Activities — the docs do not yet cover it; note the gap in `SKILL.md` instead. + +--- + +## 3. Methodology — the verification protocol + +Follow this protocol for **every** factual claim you write. No exceptions. + +### 3.1 The grep-first rule + +Before writing a flag name, command, enum, error string, env var, SDK method, conflict-policy value, or reuse-policy value, open the relevant docs file and confirm it is present verbatim. Use Grep with the exact token. Do **not** paraphrase from memory. + +Example workflow for "what subcommands does `temporal activity` support for Standalone Activities?": + +1. `Read ../documentation/docs/cli/activity.mdx` — scan all `## ` headings. +2. Transcribe only the subcommands that appear there (`cancel`, `complete`, `count`, `describe`, `execute`, `fail`, `list`, `pause`, `reset`, `result`, `start`, `terminate`, `unpause`, `update-options`). +3. Record the line number where each appears. + +### 3.2 Citation/provenance format + +Every reference file must carry inline provenance. Use HTML comments so the rendered page stays clean: + +```markdown +`temporal activity start` +``` + +Use one inline comment per non-trivial factual claim. Keep citations to local repo paths (no URLs). + +### 3.3 Anti-fabrication rules (generic) + +Refuse each of these patterns explicitly: + +1. **No "probably exists" commands/subcommands.** If a `temporal activity ` subcommand is not in `docs/cli/activity.mdx`, it doesn't exist. +2. **No "probably accepts" enum values.** Only list conflict-policy and reuse-policy values present in the docs. Do not pad the list. +3. **No "probably named" env vars, flags, or fields.** +4. **No inferred flag names.** Don't derive flags from prose. +5. **No conflating concept with interface.** "Standalone Activity" is a concept; the SDK methods and CLI subcommands are the interface — name each separately and cite each independently. +6. **No flattening of subcommand groups.** `temporal activity` has 14 subcommands; do not merge them into one example. +7. **No assumed defaults.** Don't write "default: X" unless the docs say so. + +### 3.4 Anti-fabrication rules (topic-specific) + +- **Conflict policy and reuse policy values.** The encyclopedia explicitly lists `USE_EXISTING` and `REJECT_DUPLICATES` and explicitly calls out that `TerminateExisting` / `TerminateIfRunning` are *not yet supported* in Public Preview. Do not list any policy value not present in the docs, and do not omit the unsupported-in-Preview note. +- **Public Preview limitations.** The encyclopedia calls out specific gaps (no pause/reset/update-options support in Public Preview; `TerminateExisting`/`TerminateIfRunning` unsupported). Reproduce these limitations verbatim — do not quietly drop them, and do not invent additional ones. +- **Version requirements.** Standalone Activities require Temporal CLI v1.7.0+ and Temporal Server v1.31.0+. Do not state earlier versions; do not omit the requirement. +- **TypeScript SDK.** No Standalone Activities doc exists at `docs/develop/typescript/activities/`. Do not write a TypeScript reference. In `SKILL.md`, note that TypeScript is not yet covered upstream. +- **Dual-use claim.** The encyclopedia states the *same Activity Function* can run as both Standalone and Workflow Activity with no Worker code changes. Preserve that exact framing — do not weaken it ("similar code") or strengthen it ("identical setup"). +- **CLI flag surface.** `temporal activity` shares many global flags with other `temporal` commands (auth, address, namespace, codec, TLS). Cite the CLI doc's `## Global Flags` section, do not transcribe every flag — link by reference. +- **Identifier separation.** Standalone Activities live in a separate ID space from Workflows. Do not write recipes that assume a Workflow ID can address a Standalone Activity or vice versa. +- **Billing / Cloud framing.** The encyclopedia notes fewer Billable Actions than running a single-Activity Workflow. Do not extrapolate pricing numbers; cite the encyclopedia line and stop. +- **Activity metrics reuse.** Existing Activity metrics apply — do not invent Standalone-Activity-specific metric names. Cite `docs/cloud/metrics/openmetrics/metrics-reference.mdx`. + +### 3.5 When the docs are ambiguous or silent + +Options in order of preference: + +1. Check the encyclopedia page for canonical framing before falling back to a language page. +2. Note the ambiguity in a `` comment and leave the claim out of the prose. +3. Do **not** guess. Do **not** synthesize from "this is how it probably works." + +If the user asks about TypeScript, point at the Python or Go reference and note the upstream gap. + +### 3.6 Stay descriptive, not prescriptive-beyond-docs + +Recipes (the "use Standalone Activity X to send an email reliably" pattern) are allowed if every step cites a documented API or CLI invocation. No invented orchestration patterns. + +--- + +## 4. Execution + +Use an **orchestrator + per-file subagent** shape. + +### Step 1: Read this plan end-to-end + +Especially §3.4 (topic-specific traps) and §8 (regression patterns). + +### Step 2: Set up the workspace + +Work directly in `/Users/don/work/skills/skill-temporal-developer/`. Create new files only at the paths listed in §5. Do not rename or restructure existing files. + +### Step 3: Author each reference file via a subagent + +For each file in §5 (in order), spawn a subagent. Give the subagent: + +- **The single file it owns.** One file per subagent — no cross-reading of sibling reference files. +- **The docs paths** from §1 that are relevant to that file (listed in §5). +- **The full methodology** from §3 (grep-first rule, citation format, all anti-fabrication rules including §3.4). +- **The regression patterns** from §8 — self-check against these before committing. +- **Instructions:** "You are writing `FILE_NAME`. Read ONLY the docs paths listed. Do NOT read sibling reference files. Produce one commit. Report: citation count, docs files consulted, `` markers raised." + +### Step 4: Update `SKILL.md` + +After all reference-file subagents complete, the orchestrator edits `SKILL.md` to: + +- Add a new section "Standalone Activities" under "Additional Topics" (or as its own top-level section, mirroring the existing "Task Queue Priority and Fairness" section's placement and tone). +- Point at `references/core/standalone-activities.md` and the four language-specific files. +- Note that TypeScript SDK coverage is upstream-pending. +- Do **not** restructure existing `SKILL.md` sections. + +### Step 5: Produce the log + +Append a "Standalone Activities" section to `AUTHORING_LOG.md` (create if absent) summarizing per-file citations and `` markers. + +### What NOT to do + +- Do not modify `references/typescript/`. +- Do not modify reference files outside the new Standalone Activities files and the surgical `SKILL.md` edit. +- Do not read or reference any prior conversation about Standalone Activities beyond this plan. +- Do not read the paired validation plan. +- Do not create files outside `references/` and the skill root. + +--- + +## 5. Per-file execution order + +Work in this order. Each file's correctness depends on the files above it — the core concept file establishes shared terminology that the language and CLI files inherit. + +1. **`references/core/standalone-activities.md`** — concept, when-to-use, dual-use with Workflows, key features, conflict/reuse policies (with Public Preview gaps), observability, version requirements, billing framing, identifier-space separation, and a pointer table to language pages and the CLI page. Ground truth: `docs/encyclopedia/activities/standalone-activity.mdx`, `docs/encyclopedia/activities/activities.mdx`, `docs/encyclopedia/activities/activity-execution.mdx`, `docs/evaluate/development-production-features/job-queue.mdx`, `docs/cloud/metrics/openmetrics/metrics-reference.mdx`. +2. **`references/core/standalone-activities-cli.md`** — the `temporal activity` subcommand surface as it pertains to Standalone Activities: `start`, `execute`, `result`, `list`, `count`, `describe`, `cancel`, `terminate` (and a note that `pause`, `reset`, `update-options` are not supported in Public Preview per the encyclopedia). Cite each subcommand heading and each non-trivial flag explicitly. Ground truth: `docs/cli/activity.mdx`, with a cross-cite to `docs/encyclopedia/activities/standalone-activity.mdx` for the Public Preview limitation note. +3. **`references/python/standalone-activities.md`** — Python SDK: writing the Activity (no code changes from a Workflow Activity), worker registration, `Client.execute_activity` / `start_activity`, getting a handle, waiting for result, listing, counting, Cloud connect (mTLS, API key). Ground truth: `docs/develop/python/activities/standalone-activities.mdx` only. +4. **`references/go/standalone-activities.md`** — Go SDK equivalent. Ground truth: `docs/develop/go/activities/standalone-activities.mdx` only. +5. **`references/java/standalone-activities.md`** — Java SDK equivalent. Ground truth: `docs/develop/java/activities/standalone-activities.mdx` only. +6. **`references/dotnet/standalone-activities.md`** — .NET SDK equivalent. Ground truth: `docs/develop/dotnet/activities/standalone-activities.mdx` only. +7. **`SKILL.md`** — **last**. Add a "Standalone Activities" section pointing at the six new references; note TypeScript gap. + +Why this order matters: the core concept file fixes terminology (Standalone Activity vs. Workflow Activity, conflict/reuse policy names, Public Preview limitations) that every language and CLI file then references without restating. Authoring the core file first prevents drift across the language files. SKILL.md is last so its pointers reflect what was actually written. + +--- + +## 6. Per-file done criteria + +A reference file is done when: + +1. Every command string, SDK method name, conflict/reuse policy value, error string, or API shape appears verbatim in the docs (or has a `` marker with a specific question). +2. Every name/token has a citation comment. +3. Every enum / policy value is traceable to a docs file. +4. No subcommand / field / method appears that isn't in the relevant `docs/` file's headings or tables. +5. The Public Preview limitations (no pause/reset/update-options; no `TerminateExisting`/`TerminateIfRunning`) are stated explicitly in the core file and cross-referenced from the CLI file. +6. A self-check Grep finds zero instances of the regression patterns listed in §8. + +--- + +## 7. Deliverables + +- **`AUTHORING_LOG.md`** at the skill root: per-file docs files consulted, total citation count, `` markers with questions and sources of ambiguity. +- **A git-visible diff** — one commit per reference file, one commit for the `SKILL.md` edit, so review can proceed file-by-file. + +Do not create files outside `references/` and the skill root. No `docs/` subdirectories, tutorials, `CONTRIBUTING.md`, or meta-docs. + +--- + +## 8. Regression patterns + +| Wrong pattern | Should be | Source | +|---|---|---| +| Listing `TerminateExisting` as a supported conflict policy | List `USE_EXISTING`; explicitly note `TerminateExisting` is unsupported in Public Preview | docs/encyclopedia/activities/standalone-activity.mdx:84, 110 | +| Listing `TerminateIfRunning` as a supported reuse policy | List `REJECT_DUPLICATES`; explicitly note `TerminateIfRunning` is unsupported in Public Preview | docs/encyclopedia/activities/standalone-activity.mdx:84, 110 | +| Claiming pause/reset/update-options work for Standalone Activities | State they are not supported in Public Preview but planned for GA | docs/encyclopedia/activities/standalone-activity.mdx:109 | +| Stating CLI v1.6.x or Server v1.30.x is sufficient | CLI v1.7.0+ and Server v1.31.0+ | docs/encyclopedia/activities/standalone-activity.mdx:23, 114 | +| Writing a TypeScript Standalone Activities reference | Note in SKILL.md that TypeScript coverage is upstream-pending; do not author the file | n/a (absence of `docs/develop/typescript/activities/standalone-activities.mdx`) | +| Saying Standalone Activities share an ID space with Workflows | Separate ID space from Workflows | docs/encyclopedia/activities/standalone-activity.mdx:85 | +| Saying you must rewrite Activity functions for Standalone use | Same Activity Function runs as Standalone or Workflow Activity with no code changes | docs/encyclopedia/activities/standalone-activity.mdx:56–57 | +| Inventing Standalone-Activity-specific metric names | Use existing Activity metrics; cite metrics-reference | docs/encyclopedia/activities/standalone-activity.mdx:94–96 | +| Flattening `temporal activity` subcommands into one command with flags | Document each subcommand under its own heading | docs/cli/activity.mdx:37, 62, 83, 102, 119, 162, 182, 202, 238, 310, 327, 370, 390, 446 | +| Claiming Temporal Cloud GA for Standalone Activities | Public Preview in Temporal Cloud | docs/encyclopedia/activities/standalone-activity.mdx:23, 142 | + +This table is the input to the validation plan's Check 3 (regression). Keep it in sync. + +--- + +## 9. Known correct anchors + +- Standalone Activities are Public Preview in Temporal Cloud and require CLI v1.7.0+ with Server v1.31.0+ (`docs/encyclopedia/activities/standalone-activity.mdx:23`, `:114`). +- A Standalone Activity is a top-level Activity Execution started directly by a Client, without a Workflow (`docs/encyclopedia/activities/standalone-activity.mdx:50–52`). +- The same Activity Function can be executed as a Standalone Activity and a Workflow Activity with no code changes (`docs/encyclopedia/activities/standalone-activity.mdx:56–57`). +- Conflict policy includes `USE_EXISTING`; reuse policy includes `REJECT_DUPLICATES` (`docs/encyclopedia/activities/standalone-activity.mdx:84`). +- `TerminateExisting` conflict policy and `TerminateIfRunning` reuse policy are not supported in Public Preview (`docs/encyclopedia/activities/standalone-activity.mdx:110`). +- Pause, reset, and update options are not supported in Public Preview but scheduled for GA (`docs/encyclopedia/activities/standalone-activity.mdx:109`). +- Standalone Activities have a separate ID space from Workflows (`docs/encyclopedia/activities/standalone-activity.mdx:85`). +- The `temporal activity` CLI surface includes `start`, `execute`, `result`, `list`, `count`, `describe`, `cancel`, `terminate`, plus `pause`, `reset`, `unpause`, `update-options`, `complete`, `fail` (`docs/cli/activity.mdx:37, 62, 83, 102, 119, 162, 182, 202, 238, 310, 327, 370, 390, 446`). +- The encyclopedia's GET STARTED tip lists exactly four SDK quickstarts: Go, Python, .NET, Java (`docs/encyclopedia/activities/standalone-activity.mdx:63–66`) — TypeScript is intentionally absent. +- The Temporal Dev Server has Standalone Activities enabled by default (`docs/encyclopedia/activities/standalone-activity.mdx:138`). +- All existing Activity metrics apply to Standalone Activities — no new Standalone-specific metric names (`docs/encyclopedia/activities/standalone-activity.mdx:94–96`). + +--- + +## 10. Non-goals + +- **Do not re-architect the skill.** The existing file layout, section order, and `SKILL.md` frontmatter schema are fixed. Add pointers, do not move sections. +- **Do not expand scope.** This plan covers Standalone Activities only — not Activities in general, not Workflow Activities, not Schedules. Cross-link where the docs do. +- **Do not paraphrase docs prose verbatim.** Cite, don't copy. +- **Do not write tests, CI, or tooling.** +- **Do not add meta-docs** (`CHANGELOG.md`, `CONTRIBUTING.md`) unless the user asks. +- **Do not author a TypeScript reference.** Note the upstream gap in `SKILL.md` and stop. +- **Do not change the skill version field unless the user asks.** If they do, bump the patch version of the existing `version: 0.3.2` only. + +--- + +## 11. Sibling handoff + +This skill sits alongside: + +- `skill-temporal-cli` — full `temporal` CLI reference. When the new Standalone Activities CLI reference cites a `temporal activity` subcommand, spell out the full invocation with citation to `docs/cli/activity.mdx`, but if the user is doing CLI-heavy work, point them at `skill-temporal-cli` for the broader command surface. +- `skill-temporal-cloud` — Temporal Cloud setup. The Cloud-connect snippets in the Python/Go/Java/.NET Standalone Activities references should cross-link to that skill rather than restating mTLS / API-key setup. +- `skill-temporal-triage` — incident/triage flows. If a Standalone Activity is stuck or failing, point at that skill's troubleshooting trees rather than authoring new ones here. + +Handoff disciplines: + +1. When this feature prescribes a command documented in a sibling, spell out the full invocation but cite the canonical docs file, not the sibling skill. +2. When a topic belongs to a sibling, cross-reference it; don't absorb it. + +--- + +## 12. If you get stuck + +- If a fact has no docs backing, delete it or mark it ``. +- If a whole section has no docs backing, delete the section and note it in `AUTHORING_LOG.md`. +- If the docs contradict this plan (the docs may have moved since this plan was written), trust the docs and flag the conflict in `AUTHORING_LOG.md`. + +End of plan. diff --git a/STANDALONE_ACTIVITIES_VALIDATION_PLAN.md b/STANDALONE_ACTIVITIES_VALIDATION_PLAN.md new file mode 100644 index 0000000..4e41bb0 --- /dev/null +++ b/STANDALONE_ACTIVITIES_VALIDATION_PLAN.md @@ -0,0 +1,218 @@ +# Skill Validation Plan — `Standalone Activities` + +**Reader:** you are an AI agent. The user has told you to validate the Standalone Activities additions to the Temporal Developer skill using this template. Your job has two phases: + +1. **Phase 1 — Fill this plan.** *(Done — this document is already filled.)* +2. **Phase 2 — Execute the filled plan.** Run the four-check protocol and produce a go/no-go report. + +**Critical constraint:** you must be a *different session* than the one that authored the skill. Do not read `STANDALONE_ACTIVITIES_AUTHORING_PLAN.md`, `AUTHORING_LOG.md`, or any prior conversation about the authoring. You validate from the authored files and the docs alone. + +Do not start Phase 2 until the user approves the filled plan. + +--- + + + +**Purpose:** independent verification that the Standalone Activities reference set added in commit `b0f3d87` is accurate, grounded, and free of fabrication patterns. Produce a go/no-go. + +**Non-purpose:** editing the skill. If validation finds problems, report them — do *not* fix them. + +**Scope (files added/changed by this PR):** + +- `references/core/standalone-activities.md` +- `references/core/standalone-activities-cli.md` +- `references/python/standalone-activities.md` +- `references/go/standalone-activities.md` +- `references/java/standalone-activities.md` +- `references/dotnet/standalone-activities.md` +- (For context only, not the validation target itself: the new "Standalone Activities" section in `SKILL.md`.) + +`{{SKILL_ROOT}}` = `/Users/don/work/skills/skill-temporal-developer` + +--- + +## 1. Independence requirement + +Validation must be performed by a different session than authoring. Do *not* reuse the orchestrator that ran the authoring subagents. + +The validator agents read the *authored* files above and the *docs clone* at `/Users/don/work/skills/documentation/`; they do **not** read `STANDALONE_ACTIVITIES_AUTHORING_PLAN.md` or `AUTHORING_LOG.md`. + +--- + +## 2. Source of truth + +- Primary: `/Users/don/work/skills/documentation/docs/`. Topic-relevant subtrees: + - `docs/encyclopedia/activities/standalone-activity.mdx` (concept, status, policies, limitations, Cloud) + - `docs/cli/activity.mdx` (CLI subcommand reference — every flag table) + - `docs/develop/python/activities/standalone-activities.mdx` + - `docs/develop/go/activities/standalone-activities.mdx` + - `docs/develop/java/activities/standalone-activities.mdx` + - `docs/develop/dotnet/activities/standalone-activities.mdx` + - `docs/cloud/metrics/openmetrics/metrics-reference.mdx` (metric coverage cross-reference) +- Secondary: none. The skill does not cite SDK source code, gRPC specs, or man pages for the Standalone Activities scope. + +All seven cited paths above were confirmed to exist under `documentation/docs/` during plan filling. + +Do not trust citations in the authored files as proof — follow them and confirm the cited text supports the claim. Citations can be wrong in three ways: wrong file, wrong line, or correct line with a claim subtly different from what the line actually says. + +--- + +## 3. Four-check validation protocol + +Run all four checks. The skill passes only if all four pass. + +### Check 1: citation audit + +For every inline `` comment in the six authored files: + +1. Confirm the cited file exists under `/Users/don/work/skills/documentation/docs/`. +2. Read the cited line range. +3. Confirm the authored claim is substantively supported by the cited text. + +`` markers (4 known to exist, mostly around per-language conflict/reuse-policy parameter wiring) are **not** citations — they're authored-side caveats. Note them in the report but do not count them as citation failures. + +**Pass criterion:** ≥ 98% of `` citations resolve cleanly. + +**How to run:** `grep -nE '` or a `` caveat that explains why the token is included without an upstream citation. +- The token is an ecosystem token (none expected for this skill) — would need a source-category tag. + +**Pass criterion:** zero unexplained grep-misses. + +### Check 3: regression on known bugs + +Any of these patterns appearing in the authored files is a failure. + +**Universal patterns (apply to every Temporal skill):** + +| Wrong pattern | Should be | +|---|---| +| `--profile` as a flag in `temporal` command | `--env` | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` | `TEMPORAL_TLS_CERT` | +| `TEMPORAL_TLS_CLIENT_KEY_PATH` | `TEMPORAL_TLS_KEY` | +| `TEMPORAL_TLS_SERVER_CA_CERT_PATH` | `TEMPORAL_TLS_CA` | +| `tcld service-account` (entire command group) | does not exist — should be absent | +| `--output text` / `--output jsonl` | `table, json, card` only | +| `saas-api.tmprl.cloud:7233` | port 443 | + +**Topic-specific patterns (Standalone Activities Public Preview):** + +| Wrong pattern | Should be | Source | +|---|---|---| +| `pause` / `reset` / `update-options` listed as supported for Standalone Activities | Listed as **not supported in Public Preview** | docs/encyclopedia/activities/standalone-activity.mdx:109 | +| `TerminateExisting` conflict policy presented as usable today | Listed as not supported in Public Preview | docs/encyclopedia/activities/standalone-activity.mdx:110 | +| `TerminateIfRunning` reuse policy presented as usable today | Listed as not supported in Public Preview | docs/encyclopedia/activities/standalone-activity.mdx:110 | +| Conflict/reuse policy enum values *other than* `USE_EXISTING` and `REJECT_DUPLICATES` claimed as currently available | Only those two values appear in PP docs | docs/encyclopedia/activities/standalone-activity.mdx:84 | +| `--workflow-id` marked as **required** for `temporal activity complete` / `fail` when targeting a Standalone Activity | Required for Workflow Activities only; **omit** for Standalone Activities | docs/cli/activity.mdx:80-81, 179-180 | +| CLI prerequisite stated as anything other than v1.7.0+ | `Temporal CLI v1.7.0 or higher` | docs/encyclopedia/activities/standalone-activity.mdx:114 | +| Server prerequisite stated as anything other than v1.31.0+ | `Temporal Server v1.31.0 or higher` | docs/encyclopedia/activities/standalone-activity.mdx:114 | +| Standalone Activity ID claimed to share namespace with Workflow ID | Separate ID space; not addressable as Workflow IDs | docs/encyclopedia/activities/standalone-activity.mdx:85 | +| TypeScript SDK quickstart presented as available | Coverage is upstream-pending; must be flagged as such | docs/encyclopedia/activities/standalone-activity.mdx:63-66 | +| Standalone Activities described as **GA** / **Generally Available** | **Public Preview** | docs/encyclopedia/activities/standalone-activity.mdx:21-25 | +| Claim that a Workflow is required to invoke an Activity at all | Standalone Activity is top-level, no Workflow needed | docs/encyclopedia/activities/standalone-activity.mdx:50 | +| `CountActivities` described as returning queue depth / pending tasks | Returns total count of executions matching filter — not queued tasks | docs/encyclopedia/activities/standalone-activity.mdx:101-103 | +| Claim that switching an Activity Function between Workflow-invoked and Standalone modes requires Worker code changes | No Worker code changes required | docs/encyclopedia/activities/standalone-activity.mdx:90 | +| New "Standalone-specific" metric names invented (e.g. `temporal_standalone_activity_*`) | No new metric names — reuse existing Activity metrics | docs/encyclopedia/activities/standalone-activity.mdx:94-96 | + +**Pass criterion:** zero hits against any regression pattern. + +### Check 4: independent re-verification (sampling) + +Catches *subtle-wrong*: a citation points at a real line, but the author's interpretation is off by a nuance. + +Pick **10 claims at random** per reference file (6 files × 10 = ~60 sampled claims). For each: + +1. Read *only* the claim in the authored file — not the citation. +2. Open the cited doc *independently* and read the section fresh. +3. Write down what you think the correct claim should be, given only the docs. +4. Compare your version to the authored version. + +For the CLI reference file specifically (`standalone-activities-cli.md`), bias the sample toward flag tables — the highest-density area for off-by-one cell errors (wrong "Required" status, wrong shorthand, wrong description for an adjacent flag). + +For the `core/standalone-activities.md` file, bias the sample toward the Public Preview limitations section and the conflict/reuse policy section — these are the easiest places to lose a "not" or swap an enum value. + +"Substantively different" = a reader following one would do something different than a reader following the other. Typographical / stylistic differences don't count. + +**Pass criterion:** ≥ 95% of sampled claims match. Below 95% = flag for second authoring pass. + +**How to randomize:** number all `` citations in each file from top to bottom; pick every Nth (where N = floor(total/10)) starting from a fixed offset of 1. Record the picked indices in the report. + +--- + +## 4. Execution shape + +One validator orchestrator agent. The agent: + +1. Reads this plan. +2. Reads the six authored files in `{{SKILL_ROOT}}/references/{core,python,go,java,dotnet}/` (not the authoring plan, not the `AUTHORING_LOG.md`). +3. Runs Check 1 — delegate to a per-reference-file subagent for parallelism (6 subagents). +4. Runs Check 2 — delegate per reference file (6 subagents). +5. Runs Check 3 — single pass with Grep across all six files. +6. Runs Check 4 — delegate per reference file (6 subagents); each subagent reads only the docs, not the rest of the skill. +7. Produces the report per §5. + +--- + +## 5. Deliverables + +- **`STANDALONE_ACTIVITIES_VALIDATION_REPORT.md`** at `{{SKILL_ROOT}}` with sections: + - **Go/no-go** — one-line verdict per check, overall verdict. + - **Check 1 findings** — unresolved citations, with file:line and the cited-vs-actual difference. + - **Check 2 findings** — tokens not found in docs, grouped by reference file. + - **Check 3 findings** — any regression-pattern hits, file:line, the wrong text. + - **Check 4 findings** — sampled claims that diverged from docs, with both versions. + - **Statistics** — citation count, grep-miss count, sample size, match rate. + - **VERIFY-marker inventory** — list of `` caveats with the validator's judgment of whether each is acceptable as-is or should be resolved before GA. +- Do *not* edit the authored files. Reports go in a separate file. + +Overall verdict rubric: + +- **GO** — all four checks pass their thresholds. +- **RE-RUN AUTHORING** — Check 3 has any hit, or Check 4 < 95%, or Check 1 < 98%. +- **MINOR FIXES** — Check 2 has ≤ 5 unexplained misses that look like typos or missing citation comments. + +--- + +## 6. Stop conditions + +Abort validation and escalate if: + +- Any of the six authored files is missing — nothing to validate. +- The docs clone at `/Users/don/work/skills/documentation/` is absent or empty — no source of truth. +- More than 30% of citations fail Check 1 — authoring wasn't grounded; full re-authoring needed. +- The PR added files outside `references/{core,python,go,java,dotnet}/` and `SKILL.md` (e.g. new top-level docs, tutorials) — flag as scope violation. + +--- + +## 7. What this plan does *not* do + +- **No live testing.** Running `temporal activity start` against a real server is the highest-confidence check but outside this plan's remit. +- **No prose quality grading.** Validation checks factual correctness only. +- **No scope auditing.** Whether a Standalone Activities claim belongs in `core/` vs. a per-language file is a design question answered during authoring. +- **No TypeScript coverage review.** The skill explicitly defers TS to upstream; absence of a TS file is intentional, not a finding. + +End of plan. diff --git a/STANDALONE_ACTIVITIES_VALIDATION_REPORT.md b/STANDALONE_ACTIVITIES_VALIDATION_REPORT.md new file mode 100644 index 0000000..7cd3123 --- /dev/null +++ b/STANDALONE_ACTIVITIES_VALIDATION_REPORT.md @@ -0,0 +1,176 @@ +# Standalone Activities — Validation Report + +**Plan:** `STANDALONE_ACTIVITIES_VALIDATION_PLAN.md` +**Scope:** the six reference files added in commit `b0f3d87` ("Add Standalone Activities feature reference"). +**Method:** four-check protocol per the plan, with one validator subagent per reference file (Checks 1, 2, 4) and a single regression grep pass for Check 3. + +--- + +## Go/no-go + +| Check | Verdict | Threshold | Result | +|---|---|---|---| +| Check 1 — citation audit | **PASS** | ≥ 98% resolve cleanly | 247/247 = 100% | +| Check 2 — reverse-grep / token audit | **PASS** | zero unexplained misses | 0 unexplained misses | +| Check 3 — known-bug regression | **PASS (with one INFO)** | zero hits | 0 fabrication hits; 1 universal-rule tension faithfully transcribed from upstream — see §Check 3 | +| Check 4 — independent re-verification (sampling) | **PASS** | ≥ 95% match | 60/60 = 100% sampled match | + +**Overall verdict: GO.** + +The PR is grounded, accurate, and free of fabrication. One issue surfaced by Check 3 (TLS env-var names) reflects upstream documentation rather than a skill defect — call out separately, do not block the PR. + +--- + +## Check 1 findings (citation audit) + +Zero unresolved citations across all six files. Every `` citation comment points to an existing line range in the docs clone and substantively supports the immediately preceding authored claim. + +Per-file breakdown: + +| File | Citations | Resolved | +|---|---:|---:| +| `references/core/standalone-activities.md` | 35 | 35 | +| `references/core/standalone-activities-cli.md` | 52 | 52 | +| `references/python/standalone-activities.md` | 36 | 36 | +| `references/go/standalone-activities.md` | 43 | 43 | +| `references/java/standalone-activities.md` | 43 | 43 | +| `references/dotnet/standalone-activities.md` | 38 | 38 | +| **Total** | **247** | **247** | + +Two minor non-failure observations worth recording (kept as observations, not findings): + +- `references/core/standalone-activities.md:68` cites `docs/cloud/metrics/openmetrics/metrics-reference.mdx:315`. The cited line confirms metric-series reuse but uses a slightly different framing (it mentions a `__standalone_activity` placeholder label value that the authored prose abstracts away). Substantively supported; framing is the author's, not invented. +- `references/go/standalone-activities.md:48-54` says "Temporal Dev Server has Standalone Activities enabled by default" with a citation only to `docs/develop/go/activities/standalone-activities.mdx:81` (which says "Start the Temporal development server"). The "enabled by default" half of that claim is more directly supported by `docs/encyclopedia/activities/standalone-activity.mdx:138`. Adding the encyclopedia citation would be cleaner. Not blocking. + +--- + +## Check 2 findings (reverse-grep / token audit) + +Zero unexplained grep-misses across all six files. + +- **CLI flags / subcommands** (`core/standalone-activities-cli.md`): all 14 subcommand headers and ~115 flag rows (cancel 3, complete 4, count 1, describe 3, execute 25, fail 5, list 3, pause 5, reset 15, result 2, start 25, terminate 3, unpause 13, update-options 20) match `docs/cli/activity.mdx`. Shorthands (`-a`, `-r`, `-w`, `-q`, `-t`) and Required/No columns are correct, including the case where `--task-queue` carries `-t` shorthand on `start`/`execute` but **no shorthand** on `update-options` — correctly transcribed. +- **Policy enums** (`core/standalone-activities.md` and four SDK files): `USE_EXISTING`, `REJECT_DUPLICATES` resolve to `docs/encyclopedia/activities/standalone-activity.mdx:84`; `TerminateExisting`, `TerminateIfRunning` resolve to line 110 (negative-availability claim). No other policy enum values were claimed. Where a per-language doc does not surface SDK parameter names for the policies (Python, Java, .NET — and Go for the field name on `StartActivityOptions`), the authored file inserts a `` caveat rather than fabricating a signature. Acceptable. +- **Version strings**: `v1.7.0` (CLI), `v1.31.0` (Server), and per-SDK floors (`v1.23.0` Python, `v1.41.0` Go, `v1.35.0` Java, `v1.12.0` .NET) all confirmed against the cited docs. The Python file's server-version claim is properly flagged with VERIFY because the upstream Python SDK doc itself doesn't restate the server requirement; encyclopedia carries it. +- **SDK API symbols**: every Python kwarg, Go field, Java method, and .NET property/method named in the authored files is grep-resolvable in the corresponding `docs/develop//activities/standalone-activities.mdx` page. No fabricated APIs. +- **Run-state strings**: only `CancelRequested` (cli ref); confirmed at `docs/cli/activity.mdx:47`. +- **Metric names**: no Standalone-specific metric names invented; the core file explicitly states no new metric names are introduced and reuses general Activity metric series. +- **Imports/namespaces**: Python `temporalio.client` / `temporalio.envconfig` / `temporalio.worker`; Go `go.temporal.io/sdk/{activity,client,worker,contrib/envconfig}`; Java `io.temporal.client`; .NET `Temporalio.{Client,Activities,Worker,Common.EnvConfig}` — all present in the cited per-language docs. + +--- + +## Check 3 findings (known-bug regression) + +**Universal patterns:** + +| Pattern | Hits | +|---|---| +| `--profile` flag | 0 | +| `tcld service-account` | 0 | +| `--output text` / `--output jsonl` | 0 | +| `saas-api.tmprl.cloud:7233` | 0 | +| `TEMPORAL_TLS_CLIENT_CERT_PATH` / `TEMPORAL_TLS_CLIENT_KEY_PATH` | **8 hits across 4 files** — see INFO below | +| `TEMPORAL_TLS_SERVER_CA_CERT_PATH` | 0 | + +**Topic-specific patterns (all from §3 of the plan):** zero hits. Specifically: + +- `pause` / `reset` / `update-options` are mentioned only as **not supported in Public Preview** with citations to `docs/encyclopedia/activities/standalone-activity.mdx:109` and the corresponding `docs/cli/activity.mdx` "Not supported for Standalone Activities" lines. Never presented as currently usable for Standalone Activities. +- `TerminateExisting` / `TerminateIfRunning` appear only in negative-availability statements. Never presented as currently usable. +- No conflict/reuse policy enum values other than `USE_EXISTING` / `REJECT_DUPLICATES` (positive) and `TerminateExisting` / `TerminateIfRunning` (negative) are claimed. +- `--workflow-id` is correctly described as **omitted** for Standalone Activities on `complete`/`fail` (cli ref lines 52, 122) — not required. +- Versions `v1.7.0` (CLI) and `v1.31.0` (Server) used everywhere; no off-version drift. +- "Public Preview" appears 28 times across the six files; "Generally Available" / "currently GA" / "is GA" never appears (the only `GA` reference is the cli-ref's "Support is scheduled for GA", which is a negative — `pause`/`reset`/`update-options` are not yet GA). +- TypeScript SDK is referenced exactly once (in `core/standalone-activities.md:95`) and correctly framed as upstream-pending, not as available. +- Standalone Activity ID space is correctly described as separate from Workflow IDs. +- `CountActivities` is correctly described as a count of executions matching a filter, not as queue depth. + +### INFO: TLS env-var name conflict between universal-regression rule and upstream docs + +The universal-regression table in the plan says `TEMPORAL_TLS_CLIENT_CERT_PATH` should be `TEMPORAL_TLS_CERT` (and the `_KEY_PATH` form should be `TEMPORAL_TLS_KEY`). All four SDK reference files use the long form: + +| File | Lines | +|---|---| +| `references/python/standalone-activities.md` | 306–307 | +| `references/go/standalone-activities.md` | 362–363 | +| `references/java/standalone-activities.md` | 250–251 | +| `references/dotnet/standalone-activities.md` | 268–269 | + +This is **not a fabrication**. Each upstream Standalone-Activities SDK doc uses the same long form verbatim: + +| Upstream doc | Lines | +|---|---| +| `docs/develop/python/activities/standalone-activities.mdx` | 456–457 | +| `docs/develop/go/activities/standalone-activities.mdx` | 426–427 | +| `docs/develop/java/activities/standalone-activities.mdx` | 428–429 | +| `docs/develop/dotnet/activities/standalone-activities.mdx` | 443–444 | + +Interpretation: the SDK envconfig variable names (`TEMPORAL_TLS_CLIENT_CERT_PATH` / `TEMPORAL_TLS_CLIENT_KEY_PATH`) are distinct from the CLI-level env vars (`TEMPORAL_TLS_CERT` / `TEMPORAL_TLS_KEY`). The universal-regression rule was likely written against the CLI-level form and does not account for the SDK envconfig form. + +**Recommendation (out of scope for this validation):** reconcile this in the universal-regression table — either narrow the rule to the CLI context or add the envconfig forms as accepted variants. The PR itself faithfully reflects upstream and should not be sent back through authoring on this point. **Not a blocker.** + +--- + +## Check 4 findings (independent re-verification — sampling) + +10 evenly spaced citations sampled per file (60 total). All 60 sampled claims independently re-derived from the cited docs matched the authored claims substantively. Zero divergences. + +Per-file sample sizes / match rates: + +| File | Sampled | Matched | +|---|---:|---:| +| `core/standalone-activities.md` | 10 | 10 | +| `core/standalone-activities-cli.md` | 10 | 10 | +| `python/standalone-activities.md` | 10 | 10 | +| `go/standalone-activities.md` | 10 | 10 | +| `java/standalone-activities.md` | 10 | 10 | +| `dotnet/standalone-activities.md` | 10 | 10 | + +CLI-flag-table cells (the highest off-by-one risk) were specifically sampled and matched correctly: `--reason` on `cancel`, `--raw` on `describe`, `--detail` on `fail`, `--workflow-id` required on `pause`, `--activity-id` / `--run-id` on `result`, `--reason` on `terminate`, and `--task-queue` (no shorthand) on `update-options`. + +--- + +## VERIFY-marker inventory + +Four `` markers exist across the six files. All four flag the same upstream gap — per-SDK conflict/reuse-policy parameter names are not surfaced in the SDK docs, only in the encyclopedia at the conceptual level — and correctly chose to omit the parameter signature rather than fabricate one. Each marker is judged **acceptable as-is** for the Public Preview state of the docs: + +| File | Line | Subject | Judgment | +|---|---|---|---| +| `python/standalone-activities.md` | 21 | Server v1.31.0 not stated in Python doc; sourced from encyclopedia | Acceptable | +| `python/standalone-activities.md` | 178 | `id_conflict_policy` / `id_reuse_policy` kwargs not in Python doc | Acceptable; encyclopedia covers values | +| `go/standalone-activities.md` | 214–217 | Go `StartActivityOptions` field name for conflict/reuse policy not in Go doc | Acceptable; defers to godoc | +| `java/standalone-activities.md` | 163 | Java `StartActivityOptions` builder methods for conflict/reuse policy not in Java doc | Acceptable | +| `dotnet/standalone-activities.md` | 181 | .NET `StartActivityOptions` properties for conflict/reuse policy not in .NET doc | Acceptable | + +(Note: the table lists 5 entries; the per-file scans found 4 distinct policy-related markers plus 1 server-version marker in the Python file. All justified.) + +**No `` markers exist in any file.** That tag wasn't needed because every fabrication-suspect token resolved to upstream. + +When per-SDK conflict/reuse-policy wiring lands upstream, these VERIFY markers should be revisited. They are appropriate caveats today. + +--- + +## Statistics + +- **Files validated:** 6 +- **Total lines of authored content:** 1,673 +- **Citations:** 247 (all to docs clone; no secondary sources used) +- **Citation pass rate:** 247/247 = 100% +- **Token classes checked:** CLI flags, CLI subcommands, policy enums, version strings, SDK API symbols, run-state strings, metric names, imports/namespaces (~250+ distinct tokens) +- **Unexplained grep-misses:** 0 +- **Regression-pattern hits:** 0 fabrications; 1 universal-rule tension (TLS env vars) traceable to upstream and out of skill scope to resolve +- **Check 4 sample size:** 60 (10/file) +- **Check 4 match rate:** 60/60 = 100% +- **VERIFY markers:** 5 (all justified by upstream gaps) +- **`` markers:** 0 + +--- + +## Recommendation + +**GO.** The PR meets all four-check thresholds. Merge. + +Two follow-ups, neither blocking: + +1. Consider adding `docs/encyclopedia/activities/standalone-activity.mdx:138` as a secondary citation alongside the existing dev-server citation in `references/go/standalone-activities.md:48-54` (and parallel spots in the other SDK files where the "enabled by default" claim appears) for the cleanest sourcing of the "enabled by default" half of that claim. +2. Reconcile the universal-regression rule on `TEMPORAL_TLS_CLIENT_CERT_PATH` / `TEMPORAL_TLS_CLIENT_KEY_PATH` vs. the SDK envconfig env-var names. This is a docs/regression-table problem, not a skill problem. + +Revisit the five VERIFY markers when upstream surfaces per-SDK conflict/reuse-policy parameters. diff --git a/references/core/standalone-activities-cli.md b/references/core/standalone-activities-cli.md new file mode 100644 index 0000000..da2b1cd --- /dev/null +++ b/references/core/standalone-activities-cli.md @@ -0,0 +1,323 @@ +# Standalone Activities — `temporal activity` CLI Reference + +This reference covers the `temporal activity` CLI surface as it pertains to **Standalone Activities** (a [Public Preview](https://docs.temporal.io/evaluate/development-production-features/release-stages#public-preview) feature). It transcribes flag tables verbatim from the auto-generated CLI docs and flags Public Preview gaps. + +## Prerequisites + +- **Temporal CLI v1.7.0 or higher** +- **Temporal Server v1.31.0 or higher** +- The Temporal **Dev Server has Standalone Activities enabled by default** for local testing. + +Verify the installed version with `temporal --version`; it should report v1.7.0 or higher. + +## Public Preview limitations (CLI surface) + +The following `temporal activity` subcommands exist as general activity-management commands but are **not supported for Standalone Activities** in Public Preview: + +- `pause` — Not supported for Standalone Activities. +- `reset` — Not supported for Standalone Activities. +- `update-options` — Not supported for Standalone Activities. + +These subcommands continue to work for Workflow-invoked Activities; only Standalone Activity targeting is gated. Support is scheduled for GA. + +The subcommands explicitly documented as supported for Standalone Activities are: `start`, `execute`, `result`, `list`, `count`, `describe`, `cancel`, and `terminate`. The `complete` and `fail` commands accept Standalone Activities as well (they take a Standalone Activity ID when `--workflow-id` is omitted). + +--- + +## Subcommands + +For shared auth, address, namespace, codec, and TLS flags, see the **Global Flags** reference at the bottom of `/Users/don/work/skills/documentation/docs/cli/activity.mdx` (lines 507–544). They apply to every subcommand below and are not transcribed here. + +### `cancel` + +Request cancellation of a Standalone Activity. Transitions run state to `CancelRequested`; if the Activity is heartbeating, a cancellation error is delivered on the next heartbeat response. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. | +| `--reason` | No | Reason for cancellation. | +| `--run-id`, `-r` | No | Activity Run ID. If not set, targets the latest run. | + + + +### `complete` + +Mark an Activity as successfully finished and return a JSON result. For a Standalone Activity, omit `--workflow-id`; `--run-id` then refers to the Activity Run ID. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. May be a Workflow Activity or Standalone Activity ID. | +| `--result` | Yes | Result `JSON` to return. | +| `--run-id`, `-r` | No | Run ID. Workflow Run ID for workflow Activities; Activity Run ID for Standalone Activities. | +| `--workflow-id`, `-w` | No | Workflow ID. Required for workflow Activities. Omit for Standalone Activities. | + + + +### `count` + +Return a count of Standalone Activities matching a filter. + +| Flag | Required | Description | +|------|----------|-------------| +| `--query`, `-q` | No | Query to filter Activity Executions to count. | + + + +### `describe` + +Display information about a Standalone Activity. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. | +| `--raw` | No | Print properties without changing their format. | +| `--run-id`, `-r` | No | Activity Run ID. If not set, targets the latest run. | + + + +### `execute` + +Start a new Standalone Activity and **block until it completes**, printing the result to stdout. Either `--start-to-close-timeout` or `--schedule-to-close-timeout` is required. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. | +| `--fairness-key` | No | Fairness key (max 64 bytes) for proportional task dispatch. | +| `--fairness-weight` | No | Weight `[0.001-1000]` for this fairness key. | +| `--headers` | No | Temporal activity headers in `KEY=VALUE` format. May be passed multiple times. | +| `--heartbeat-timeout` | No | Maximum time between successful Worker heartbeats. | +| `--id-conflict-policy` | No | Policy when an Activity with the same ID is currently running. Accepted values: `Fail`, `UseExisting`. | +| `--id-reuse-policy` | No | Policy when an Activity with the same ID exists and has completed. Accepted values: `AllowDuplicate`, `AllowDuplicateFailedOnly`, `RejectDuplicate`. | +| `--input`, `-i` | No | Input value (JSON, or use `--input-meta`). Repeatable. | +| `--input-base64` | No | Assume inputs are base64-encoded. | +| `--input-file` | No | Path(s) to input file(s). Repeatable. | +| `--input-meta` | No | Input payload metadata as `KEY=VALUE`. | +| `--priority-key` | No | Priority key (1–5, lower = higher priority). Default 3. | +| `--retry-backoff-coefficient` | No | Coefficient for the next retry interval. Must be ≥1. | +| `--retry-initial-interval` | No | Interval of the first retry. | +| `--retry-maximum-attempts` | No | Maximum attempts. `1` disables retries; `0` is unlimited. | +| `--retry-maximum-interval` | No | Maximum interval between retries. | +| `--schedule-to-close-timeout` | No | Maximum total time including retries. | +| `--schedule-to-start-timeout` | No | Maximum time a task can sit in the queue. | +| `--search-attribute` | No | Search Attribute in `KEY=VALUE`. Repeatable. | +| `--start-to-close-timeout` | No | Maximum time for a single attempt. | +| `--static-details` | No | Static Activity details for UIs (Markdown). _(Experimental)_ | +| `--static-summary` | No | Static Activity summary for UIs (Markdown). _(Experimental)_ | +| `--task-queue`, `-t` | Yes | Activity task queue. | +| `--type` | Yes | Activity Type name. | + + + +### `fail` + +Fail an Activity, marking it as having encountered an error. For Standalone Activities, omit `--workflow-id`. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. May be a Workflow Activity or Standalone Activity ID. | +| `--detail` | No | Failure detail (JSON). Attached as the failure details payload. | +| `--reason` | No | Failure reason. Attached as the failure message. | +| `--run-id`, `-r` | No | Run ID. Workflow Run ID for workflow Activities; Activity Run ID for Standalone Activities. | +| `--workflow-id`, `-w` | No | Workflow ID. Required for workflow Activities. Omit for Standalone Activities. | + + + +### `list` + +List Standalone Activities. Use `--query` to filter results. + +| Flag | Required | Description | +|------|----------|-------------| +| `--limit` | No | Maximum number of Activity Executions to display. | +| `--page-size` | No | Maximum number of Activity Executions to fetch per page. | +| `--query`, `-q` | No | Query to filter the Activity Executions to list. | + + + +### `pause` + +> **Not supported for Standalone Activities** in Public Preview. Use this only for Workflow-invoked Activities; scheduled for GA. + +Pauses an Activity so that it will not run again until unpaused. See `unpause` to resume, or `reset` to also restart from the beginning. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | No | Activity ID to pause. Mutually exclusive with `--activity-type`. | +| `--activity-type` | No | All activities of this Activity Type will be paused. _(Experimental for Type-targeting.)_ | +| `--identity` | No | Identity of the user or client submitting the request. | +| `--run-id`, `-r` | No | Run ID. | +| `--workflow-id`, `-w` | Yes | Workflow ID. | + + + +### `reset` + +> **Not supported for Standalone Activities** in Public Preview. Use this only for Workflow-invoked Activities. + +Resets an Activity as if it were first being scheduled — resetting attempts, timeout, and optionally heartbeat details. Either `--activity-id`, `--activity-type`, or `--match-all` must be specified. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | No | Activity ID to reset. Requires `--workflow-id`. Mutually exclusive with `--query`, `--match-all`, `--activity-type`. | +| `--activity-type` | No | Activities of this Type will be reset. _(Experimental.)_ | +| `--headers` | No | Temporal workflow headers in `KEY=VALUE`. Repeatable. | +| `--jitter` | No | Reset within a random window inside this duration. Only with `--query`. | +| `--keep-paused` | No | If the activity was paused, keep it paused. | +| `--match-all` | No | Reset every activity. _(Experimental.)_ | +| `--query`, `-q` | No | SQL-like List Filter for batch reset. _(Experimental.)_ | +| `--reason` | No | Reason for batch operation. Only with `--query`. | +| `--reset-attempts` | No | Reset the activity attempts. | +| `--reset-heartbeats` | No | Reset the Activity's heartbeats. Only works with `--reset-attempts`. | +| `--restore-original-options` | No | Restore the original options of the activity. | +| `--rps` | No | Limit batch's requests per second. Only with `--query`. | +| `--run-id`, `-r` | No | Run ID. Only with `--workflow-id`. | +| `--workflow-id`, `-w` | No | Workflow ID. Set either `--workflow-id` or `--query`. | +| `--yes`, `-y` | No | Skip confirmation. Only with `--query`. | + + + +### `result` + +Wait for a Standalone Activity to complete and output the result. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. | +| `--run-id`, `-r` | No | Activity Run ID. If not set, targets the latest run. | + + + +### `start` + +Start a new Standalone Activity. Outputs the Activity ID and Run ID and returns immediately (fire-and-forget). Either `--start-to-close-timeout` or `--schedule-to-close-timeout` is required. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. | +| `--fairness-key` | No | Fairness key (max 64 bytes). | +| `--fairness-weight` | No | Weight `[0.001-1000]`. | +| `--headers` | No | Temporal activity headers in `KEY=VALUE`. Repeatable. | +| `--heartbeat-timeout` | No | Maximum time between successful Worker heartbeats. | +| `--id-conflict-policy` | No | Accepted: `Fail`, `UseExisting`. | +| `--id-reuse-policy` | No | Accepted: `AllowDuplicate`, `AllowDuplicateFailedOnly`, `RejectDuplicate`. | +| `--input`, `-i` | No | Input value. Repeatable. | +| `--input-base64` | No | Assume inputs are base64-encoded. | +| `--input-file` | No | Path(s) to input file(s). Repeatable. | +| `--input-meta` | No | Input payload metadata as `KEY=VALUE`. | +| `--priority-key` | No | Priority key (1–5, lower = higher priority). Default 3. | +| `--retry-backoff-coefficient` | No | Must be ≥1. | +| `--retry-initial-interval` | No | First retry interval. | +| `--retry-maximum-attempts` | No | `1` disables retries; `0` is unlimited. | +| `--retry-maximum-interval` | No | Cap between retries. | +| `--schedule-to-close-timeout` | No | Total deadline including retries. | +| `--schedule-to-start-timeout` | No | Queue waiting deadline. | +| `--search-attribute` | No | Search Attribute in `KEY=VALUE`. Repeatable. | +| `--start-to-close-timeout` | No | Single-attempt deadline. | +| `--static-details` | No | Static Activity details (Markdown). _(Experimental)_ | +| `--static-summary` | No | Static Activity summary (Markdown). _(Experimental)_ | +| `--task-queue`, `-t` | Yes | Activity task queue. | +| `--type` | Yes | Activity Type name. | + + + +### `terminate` + +Terminate a Standalone Activity. Activity code cannot see or respond to terminations. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | Yes | Activity ID. | +| `--reason` | No | Reason for termination. Defaults to a message with the current user's name. | +| `--run-id`, `-r` | No | Activity Run ID. If not set, targets the latest run. | + + + +### `unpause` + +Re-schedule a previously-paused Activity for execution. **Not supported for Standalone Activities.** (Public Preview gap is `pause`/`reset`/`update-options`; `unpause` only ever applies to paused Activities, which on Standalone Activities cannot exist in Public Preview.) + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | No | Activity ID to unpause. Requires `--workflow-id`. Mutually exclusive with `--query`, `--match-all`, `--activity-type`. | +| `--activity-type` | No | Activities of this Type will unpause. _(Experimental.)_ | +| `--headers` | No | Temporal workflow headers in `KEY=VALUE`. Repeatable. | +| `--jitter` | No | Random start window. Only with `--query`. | +| `--match-all` | No | Unpause every paused activity. _(Experimental.)_ | +| `--query`, `-q` | No | SQL-like List Filter for batch unpause. _(Experimental.)_ | +| `--reason` | No | Reason for batch operation. Only with `--query`. | +| `--reset-attempts` | No | Reset the activity attempts. | +| `--reset-heartbeats` | No | Reset heartbeats. Only works with `--reset-attempts`. | +| `--rps` | No | Limit batch's requests per second. Only with `--query`. | +| `--run-id`, `-r` | No | Run ID. Only with `--workflow-id`. | +| `--workflow-id`, `-w` | No | Workflow ID. Set either `--workflow-id` or `--query`. | +| `--yes`, `-y` | No | Skip confirmation. Only with `--query`. | + + + +### `update-options` + +> **Not supported for Standalone Activities** in Public Preview. Use this only for Workflow-invoked Activities; scheduled for GA. + +Update the options of a running Activity passed in from a Workflow. Updates are incremental. Either `--activity-id`, `--activity-type`, or `--match-all` must be specified. + +| Flag | Required | Description | +|------|----------|-------------| +| `--activity-id`, `-a` | No | Activity ID. Requires `--workflow-id`. | +| `--activity-type` | No | Activities of this Type will be updated. _(Experimental.)_ | +| `--headers` | No | Temporal workflow headers in `KEY=VALUE`. Repeatable. | +| `--heartbeat-timeout` | No | Maximum time between successful worker heartbeats. | +| `--match-all` | No | Update every activity. _(Experimental.)_ | +| `--query`, `-q` | No | SQL-like List Filter for batch update. _(Experimental.)_ | +| `--reason` | No | Reason for batch operation. Only with `--query`. | +| `--restore-original-options` | No | Restore the original options of the activity. | +| `--retry-backoff-coefficient` | No | Must be ≥1. | +| `--retry-initial-interval` | No | First retry interval. | +| `--retry-maximum-attempts` | No | `1` disables retries; `0` is unlimited. | +| `--retry-maximum-interval` | No | Cap between retries. | +| `--rps` | No | Limit batch's requests per second. Only with `--query`. | +| `--run-id`, `-r` | No | Run ID. Only with `--workflow-id`. | +| `--schedule-to-close-timeout` | No | Total deadline including retries. | +| `--schedule-to-start-timeout` | No | Queue waiting deadline. | +| `--start-to-close-timeout` | No | Single-attempt deadline. | +| `--task-queue` | No | Name of the task queue. | +| `--workflow-id`, `-w` | No | Workflow ID. Set either `--workflow-id` or `--query`. | +| `--yes`, `-y` | No | Skip confirmation. Only with `--query`. | + + + +--- + +## Global Flags + +Shared flags for `--address`, `--api-key`, `--namespace`, `--codec-endpoint`/`--codec-auth`, `--tls*`, `--grpc-meta`, `--identity`, `--output`, etc. live in the `## Global Flags` section of the docs file. See `/Users/don/work/skills/documentation/docs/cli/activity.mdx` lines 507–544. + +--- + +## Common flows + +### Start-and-wait (synchronous) + +Use `execute` to start a Standalone Activity and block on its result. The result is printed to stdout when the Activity completes. + +### Fire-and-forget, retrieve later + +1. Use `start` to schedule the Activity; the command outputs the Activity ID and Run ID. +2. Use `result` later (from any machine) with the same `--activity-id` to block until completion and read the output. + +### Listing and counting + +- Use `list` with `--query` (a [List Filter](https://docs.temporal.io/list-filter)) to enumerate Standalone Activity Executions. +- Use `count` with the same query syntax to obtain a total count without paging. + +### Inspect a single Activity + +Use `describe` with `--activity-id` (and optionally `--run-id`) to view current state, attempts, and the latest failure. + +### Cancel vs. terminate + +- `cancel` requests cooperative cancellation; the Activity sees the cancellation on its next heartbeat and may run cleanup. +- `terminate` ends the Activity unilaterally; Activity code cannot see or respond. + +### External completion + +If the Activity uses manual completion, use `complete` (with `--workflow-id` omitted) to deliver the result, or `fail` to deliver an error. diff --git a/references/core/standalone-activities.md b/references/core/standalone-activities.md new file mode 100644 index 0000000..4b94fc4 --- /dev/null +++ b/references/core/standalone-activities.md @@ -0,0 +1,95 @@ +# Standalone Activities + +A **Standalone Activity** is a top-level [Activity Execution](../../../documentation/docs/encyclopedia/activities/activity-execution.mdx) started directly by a Temporal Client, without a Workflow wrapping it. + +This reference covers the concept. For language-specific code, see the per-SDK references listed at the bottom. For the `temporal activity` CLI, see `references/core/standalone-activities-cli.md`. + +## Status and dependencies + +Standalone Activities are a **Public Preview** feature. They require: + +- **Temporal CLI v1.7.0 or higher** +- **Temporal Server v1.31.0 or higher** + +The Temporal Dev Server has Standalone Activities enabled by default for local testing. + +## When to use a Standalone Activity vs. a Workflow + +- If you need to **orchestrate multiple Activities**, use a [Workflow](../../../documentation/docs/encyclopedia/activities/activities.mdx). +- If you just need to **execute a single Activity**, use a Standalone Activity. + +Standalone Activities are framed as Temporal's [job queue](../../../documentation/docs/evaluate/development-production-features/job-queue.mdx) — the simplest way to run durable, retryable tasks on Temporal. + +Typical use cases include sending an email, processing a webhook, syncing data, or executing a single function reliably with built-in retries and timeouts. + +## Dual use: same Activity Function, two execution modes + +You write your Activity Functions the same way for both. **The same Activity Function can be executed as a Standalone Activity and as a Workflow Activity with no code changes.** No Worker code changes are required to switch between the two modes. + +## Key features + +- **Top-level execution** — execute any Temporal Activity as a top-level primitive without the overhead of a Workflow. +- **Async job processing model** — schedule → dispatch → process → result. +- **No head-of-line blocking** — a slow job doesn't block dispatch of other Tasks. +- **Arbitrary-length jobs** — heartbeats provide liveness and progress checkpointing. +- **At-least-once execution by default** with a native retry policy and timeouts. +- **At-most-once execution** if retry max attempts is `1`. +- **Addressable** — get an Activity ID / Run ID and use it to fetch the result, cancel, or terminate the execution. +- **Deduplication** — controlled via conflict and reuse policies (see below). +- **Separate ID space from Workflows** — Standalone Activities are a different kind of top-level execution; their IDs do not collide with, and are not addressable as, Workflow IDs. +- **Priority and fairness** — multi-tenant fairness, weighted priority tiers, and safeguards against starvation of lower-weighted tasks. +- **Visibility** — list Activity Executions and view status, retry count, and last error. +- **Manual completion by ID (or token)** — ignore the Activity return value and wait for external completion. +- **Activity metrics** — including counts for success, failure, timeout, and cancel. + +### Conflict and reuse policies (Public Preview) + +Only the values below appear in the upstream documentation for Public Preview: + +- Conflict policy: `USE_EXISTING` +- Reuse policy: `REJECT_DUPLICATES` + +The following are **not** supported in Public Preview: + +- `TerminateExisting` conflict policy +- `TerminateIfRunning` reuse policy + +Do not assume any other enum values exist for Standalone Activities until they are documented upstream. + +## Public Preview limitations + +The Public Preview has the following known limitations: + +- **Pause, reset, and update options are not supported in Public Preview but are scheduled for GA.** +- **`TerminateExisting` conflict policy / `TerminateIfRunning` reuse policy is not supported yet.** + +## Observability + +All existing [Activity metrics](../../../documentation/docs/cloud/metrics/openmetrics/metrics-reference.mdx) apply to Standalone Activities. This includes counts for scheduled, started, completed, failed, timed out, and canceled activities. No new Standalone-specific metric names are introduced; query the same Activity metric series you already use for Workflow Activities. + +You can query Standalone Activity Executions using [List Filters](../../../documentation/docs/encyclopedia/visibility.mdx) by type, status, task queue, and other attributes — either through an SDK or via the `temporal activity list` CLI command. + +`CountActivities` returns the total number of Standalone Activity Executions matching a filter, analogous to counting Workflow Executions. This is the total count of executions (running, completed, failed, etc.) — **not** the number of queued tasks. + +## Temporal Cloud support + +Standalone Activities in Temporal Cloud are available as a **Public Preview** feature. + +## Billing framing (Temporal Cloud) + +Running an Activity as a Standalone Activity results in **fewer Billable Actions** than running the same single Activity inside a Workflow. If your Activity Execution is short-lived, you may also see lower latency due to fewer Worker round-trips. Refer to the Temporal Cloud Actions Usage documentation for the authoritative count semantics; do not extrapolate specific numeric ratios. + +## Where to go next + +Per-language references in this skill: + +- `references/python/standalone-activities.md` +- `references/go/standalone-activities.md` +- `references/java/standalone-activities.md` +- `references/dotnet/standalone-activities.md` + +CLI reference in this skill: + +- `references/core/standalone-activities-cli.md` + +> **TypeScript SDK note:** Upstream documentation does not currently include a TypeScript Standalone Activities quickstart or reference. Coverage is upstream-pending; do not assume parity with Python/Go/Java/.NET until the docs land. diff --git a/references/dotnet/standalone-activities.md b/references/dotnet/standalone-activities.md new file mode 100644 index 0000000..f48aa02 --- /dev/null +++ b/references/dotnet/standalone-activities.md @@ -0,0 +1,285 @@ +# Standalone Activities — .NET SDK + +Standalone Activities run independently, without being orchestrated by a Workflow. You start them directly from a Temporal Client. Support in the Temporal .NET SDK is at **Public Preview**. + + +The way you write the Activity and register it with a Worker is identical to a Workflow Activity — the same Activity Function can be executed both as a Standalone Activity and as a Workflow Activity with no code changes. + + + +## Prerequisites + +- **.NET 8.0+** + +- **Temporal .NET SDK v1.12.0 or higher** + +- **Temporal CLI v1.7.0 or higher** + +- **Temporal Server v1.31.0 or higher** + + +Start a local development server (the Temporal Dev Server has Standalone Activities enabled by default): + +```bash +temporal server start-dev +``` + + + +### Public Preview limitations + +- Pause, reset, and update options are not supported in Public Preview but are scheduled for GA. +- The `TerminateExisting` conflict policy / `TerminateIfRunning` reuse policy is not supported yet. + + + +## Define your Activity + +An Activity in the .NET SDK is a method decorated with the `[Activity]` attribute. The way you write a Standalone Activity is identical to how you write an Activity orchestrated by a Workflow — the same Activity can be executed both as a Standalone Activity and as a Workflow Activity. + + +```csharp +namespace TemporalioSamples.StandaloneActivity; + +using Temporalio.Activities; + +public static class MyActivities +{ + [Activity] + public static Task ComposeGreetingAsync(ComposeGreetingInput input) => + Task.FromResult($"{input.Greeting}, {input.Name}!"); +} + +public record ComposeGreetingInput(string Greeting, string Name); +``` + + +## Run a Worker with the Activity registered + +Running a Worker for Standalone Activities is the same as running a Worker for Workflow Activities — create a Worker, register the Activity, and run the Worker. The Worker doesn't need to know whether the Activity will be invoked from a Workflow or as a Standalone Activity. + + +```csharp +using Microsoft.Extensions.Logging; +using Temporalio.Client; +using Temporalio.Common.EnvConfig; +using Temporalio.Worker; +using TemporalioSamples.StandaloneActivity; + +var connectOptions = ClientEnvConfig.LoadClientConnectOptions(); +connectOptions.TargetHost ??= "localhost:7233"; +connectOptions.LoggerFactory = LoggerFactory.Create(builder => + builder. + AddSimpleConsole(options => options.TimestampFormat = "[HH:mm:ss] "). + SetMinimumLevel(LogLevel.Information)); +var client = await TemporalClient.ConnectAsync(connectOptions); + +const string taskQueue = "standalone-activity-sample"; + +using var tokenSource = new CancellationTokenSource(); +Console.CancelKeyPress += (_, eventArgs) => +{ + tokenSource.Cancel(); + eventArgs.Cancel = true; +}; + +using var worker = new TemporalWorker( + client, + new TemporalWorkerOptions(taskQueue). + AddActivity(MyActivities.ComposeGreetingAsync)); + +await worker.ExecuteAsync(tokenSource.Token); +``` + + +The samples use `ClientEnvConfig.LoadClientConnectOptions()` so the same code works against a local dev server and Temporal Cloud — see [Run with Temporal Cloud](#run-with-temporal-cloud) below. + + +## Execute a Standalone Activity (wait for the result) + +Use `client.ExecuteActivityAsync()` to execute a Standalone Activity and wait for the result. Call this from your application code, not from inside a Workflow Definition. It durably enqueues the Activity in the Temporal Server, waits for it to be executed on your Worker, and returns the result. + + +```csharp +using Temporalio.Client; +using Temporalio.Common.EnvConfig; +using TemporalioSamples.StandaloneActivity; + +var connectOptions = ClientEnvConfig.LoadClientConnectOptions(); +connectOptions.TargetHost ??= "localhost:7233"; +var client = await TemporalClient.ConnectAsync(connectOptions); + +var result = await client.ExecuteActivityAsync( + () => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")), + new("standalone-activity-id", "standalone-activity-sample") + { + ScheduleToCloseTimeout = TimeSpan.FromSeconds(10), + }); +Console.WriteLine($"Activity result: {result}"); +``` + + +You can pass the Activity as either a lambda expression (type-safe) or a string Activity type name: + +```csharp +// Using a lambda expression (type-safe) +var result = await client.ExecuteActivityAsync( + () => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")), + new("standalone-activity-id", "standalone-activity-sample") + { + ScheduleToCloseTimeout = TimeSpan.FromSeconds(10), + }); + +// Using a string type name +var result = await client.ExecuteActivityAsync( + "ComposeGreeting", + new object?[] { new ComposeGreetingInput("Hello", "World") }, + new("standalone-activity-id", "standalone-activity-sample") + { + ScheduleToCloseTimeout = TimeSpan.FromSeconds(10), + }); +``` + + +`StartActivityOptions` requires `Id`, `TaskQueue`, and at least one of `ScheduleToCloseTimeout` or `StartToCloseTimeout`. See the [`StartActivityOptions`](https://dotnet.temporal.io/api/Temporalio.Client.StartActivityOptions.html) API reference for the full set of options. + + +## Start a Standalone Activity without waiting for the result + +Use `client.StartActivityAsync()` to start a Standalone Activity and get a handle without waiting for the result: + + +```csharp +using Temporalio.Client; +using Temporalio.Common.EnvConfig; +using TemporalioSamples.StandaloneActivity; + +var connectOptions = ClientEnvConfig.LoadClientConnectOptions(); +connectOptions.TargetHost ??= "localhost:7233"; +var client = await TemporalClient.ConnectAsync(connectOptions); + +var handle = await client.StartActivityAsync( + () => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")), + new("standalone-activity-id", "standalone-activity-sample") + { + ScheduleToCloseTimeout = TimeSpan.FromSeconds(10), + }); +Console.WriteLine($"Started activity: {handle.Id}"); + +// Wait for the result later +var result = await handle.GetResultAsync(); +Console.WriteLine($"Activity result: {result}"); +``` + + +### Conflict policy and reuse policy + +Standalone Activities support deduplication via conflict policy (e.g. `USE_EXISTING`) and reuse policy (e.g. `REJECT_DUPLICATES`). Note that during Public Preview, `TerminateExisting` conflict policy / `TerminateIfRunning` reuse policy are not supported yet. + + + + + +## Get a handle to an existing Standalone Activity + +Use `client.GetActivityHandle()` to create a handle to a previously started Standalone Activity: + + +```csharp +// Without a known result type +var handle = client.GetActivityHandle("my-activity-id", runId: "the-run-id"); + +// With a known result type +var typedHandle = client.GetActivityHandle("my-activity-id", runId: "the-run-id"); +``` + + +You can use the handle to wait for the result, describe, cancel, or terminate the Activity. + + +## Wait for the result of a Standalone Activity + +Calling `client.ExecuteActivityAsync()` is equivalent to calling `client.StartActivityAsync()` to durably enqueue the Standalone Activity, then `await handle.GetResultAsync()` to wait for the Activity to be executed and return the result: + + +```csharp +var result = await handle.GetResultAsync(); +``` + + +## List Standalone Activities + +Use `client.ListActivitiesAsync()` to list Standalone Activity Executions that match a List Filter query. The result is an `IAsyncEnumerable` that yields `ActivityExecution` entries. + +These APIs return only Standalone Activity Executions. Activities running inside Workflows are not included. + + +```csharp +using Temporalio.Client; +using Temporalio.Common.EnvConfig; + +var connectOptions = ClientEnvConfig.LoadClientConnectOptions(); +connectOptions.TargetHost ??= "localhost:7233"; +var client = await TemporalClient.ConnectAsync(connectOptions); + +await foreach (var info in client.ListActivitiesAsync( + "TaskQueue = 'standalone-activity-sample'")) +{ + Console.WriteLine( + $"ActivityID: {info.ActivityId}, Type: {info.ActivityType}, Status: {info.Status}"); +} +``` + + +The query parameter accepts the same List Filter syntax used for Workflow Visibility — for example, `"ActivityType = 'ComposeGreeting' AND Status = 'Running'"`. + + +## Count Standalone Activities + +Use `client.CountActivitiesAsync()` to count Standalone Activity Executions that match a List Filter query. This returns the total count of executions (running, completed, failed, etc.) — not the number of queued tasks. It works the same way as counting Workflow Executions. + + +```csharp +using Temporalio.Client; +using Temporalio.Common.EnvConfig; + +var connectOptions = ClientEnvConfig.LoadClientConnectOptions(); +connectOptions.TargetHost ??= "localhost:7233"; +var client = await TemporalClient.ConnectAsync(connectOptions); + +var resp = await client.CountActivitiesAsync( + "TaskQueue = 'standalone-activity-sample'"); +Console.WriteLine($"Total activities: {resp.Count}"); +``` + + +## Run with Temporal Cloud + +The code samples use `ClientEnvConfig.LoadClientConnectOptions()`, so the same code works against Temporal Cloud — just configure the connection via environment variables or a TOML profile. No code changes are needed. + + +### Connect with mTLS + +Set these environment variables with values from your Temporal Cloud Namespace settings: + +``` +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem' +export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key' +``` + + +### Connect with an API key + +Set these environment variables with values from your Temporal Cloud API key settings: + +``` +export TEMPORAL_ADDRESS=..api.temporal.io:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_API_KEY= +``` + + +Then run the Worker and starter code as shown in the earlier sections. + diff --git a/references/go/standalone-activities.md b/references/go/standalone-activities.md new file mode 100644 index 0000000..9e26d09 --- /dev/null +++ b/references/go/standalone-activities.md @@ -0,0 +1,380 @@ +# Standalone Activities — Go SDK Reference + +Standalone Activities are Activity Executions that run independently, without +being orchestrated by a Workflow. Instead of starting an Activity from inside a +Workflow Definition with `workflow.ExecuteActivity()`, you start a Standalone +Activity directly from a Temporal Client using `client.ExecuteActivity()`. + + +The Activity Definition and Worker registration are identical to regular +(Workflow) Activities — only the execution path differs. The same Activity +Function can be executed as a Standalone Activity and as a Workflow Activity +with no code changes. + + + +> Public Preview: Go SDK support for Standalone Activities is at Public +> Preview. `TerminateExisting` conflict policy / `TerminateIfRunning` reuse +> policy is not supported yet, and pause / reset / update options are not +> supported in Public Preview but are scheduled for GA. + + + +--- + +## 1. Prerequisites + +- **Go** 1.22+ +- **Temporal Go SDK** v1.41.0 or higher +- **Temporal CLI** v1.7.0 or higher +- **Temporal Server** v1.31.0 or higher (Standalone Activities require this) + + + +Install the CLI with Homebrew: + +```bash +brew install temporal +``` + + +Verify: + +```bash +temporal --version +``` + + +Start the local development server (the Temporal Dev Server has Standalone +Activities enabled by default): + +``` +temporal server start-dev +``` + + +The server listens on `localhost:7233` and the Web UI is at +`http://localhost:8233`. Standalone Activities are accessible from the nav bar +in the Web UI. + + +--- + +## 2. Writing an Activity Function + +Define your Activity in a shared file so both the Worker and the starter can +reference it. The signature and body are identical to a Workflow Activity — no +Standalone-specific code is required. + + +```go +package helloworld + +import ( + "context" + "go.temporal.io/sdk/activity" +) + +func Activity(ctx context.Context, name string) (string, error) { + logger := activity.GetLogger(ctx) + logger.Info("Activity", "name", name) + return "Hello " + name + "!", nil +} +``` + + +--- + +## 3. Running a Worker with the Activity registered + +Running a Worker for Standalone Activities is the same as running a Worker for +Workflow-driven Activities — create a Worker, register the Activity, and call +`Run()`. The Worker doesn't need to know whether the Activity will be invoked +from a Workflow or as a Standalone Activity. + + +```go +package main + +import ( + "github.com/temporalio/samples-go/standalone-activity/helloworld" + "go.temporal.io/sdk/client" + "go.temporal.io/sdk/contrib/envconfig" + "go.temporal.io/sdk/worker" + "log" +) + +func main() { + c, err := client.Dial(envconfig.MustLoadDefaultClientOptions()) + if err != nil { + log.Fatalln("Unable to create client", err) + } + defer c.Close() + + w := worker.New(c, "standalone-activity-helloworld", worker.Options{}) + + w.RegisterActivity(helloworld.Activity) + + err = w.Run(worker.InterruptCh()) + if err != nil { + log.Fatalln("Unable to start worker", err) + } +} +``` + + +Run the Worker: + +``` +go run standalone-activity/helloworld/worker/main.go +``` + + +--- + +## 4. Executing a Standalone Activity (wait-for-result) + +Use [`client.ExecuteActivity()`](https://pkg.go.dev/go.temporal.io/sdk/client#Client) +from application code (not from inside a Workflow Definition) to start a +Standalone Activity Execution. It returns an `ActivityHandle` that you can use +to get the result, describe, cancel, or terminate the Activity. + + +`client.StartActivityOptions` requires `ID`, `TaskQueue`, and at least one of +`ScheduleToCloseTimeout` or `StartToCloseTimeout`. + + +```go +activityOptions := client.StartActivityOptions{ + ID: "standalone_activity_helloworld_ActivityID", + TaskQueue: "standalone-activity-helloworld", + ScheduleToCloseTimeout: 10 * time.Second, +} + +handle, err := c.ExecuteActivity(context.Background(), activityOptions, helloworld.Activity, "Temporal") +if err != nil { + log.Fatalln("Unable to execute activity", err) +} + +log.Println("Started standalone activity", "ActivityID", handle.GetID(), "RunID", handle.GetRunID()) + +var result string +err = handle.Get(context.Background(), &result) +if err != nil { + log.Fatalln("Unable get standalone activity result", err) +} +log.Println("Activity result:", result) +``` + + +You can pass the Activity as either a function reference or a string Activity +type name: + +```go +handle, err := c.ExecuteActivity(ctx, options, helloworld.Activity, "arg1") + +// Using a string type name +handle, err := c.ExecuteActivity(ctx, options, "Activity", "arg1") +``` + + +Or use the Temporal CLI: + +```bash +temporal activity execute \ + --type Activity \ + --activity-id standalone_activity_helloworld_ActivityID \ + --task-queue standalone-activity-helloworld \ + --schedule-to-close-timeout 10s \ + --input '"Temporal"' +``` + + +--- + +## 5. Starting a Standalone Activity (without waiting) and dedup policies + +`client.ExecuteActivity()` returns an `ActivityHandle` immediately — you do not +have to call `handle.Get()` to wait for the result. You can return the +`ActivityID` / `RunID` to a caller and pick the Activity up later via a handle. + + + +For deduplication, Standalone Activities support **conflict policy** +(`USE_EXISTING`, ...) and **reuse policy** (`REJECT_DUPLICATES`, ...). +`TerminateExisting` conflict policy and `TerminateIfRunning` reuse policy are +**not supported** in Public Preview. + + + +See [`StartActivityOptions`](https://pkg.go.dev/go.temporal.io/sdk/client#StartActivityOptions) +in the Go SDK API reference for the full set of options. + + + + +--- + +## 6. Getting a handle to an existing Standalone Activity + +Use `client.GetActivityHandle()` to create a handle to a previously started +Standalone Activity. This is analogous to `client.GetWorkflow()` for Workflow +Executions. Both `ActivityID` and `RunID` are required. + + +```go +handle := c.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: "standalone_activity_helloworld_ActivityID", + RunID: "the-run-id", +}) + +// Use the handle to get the result, describe, cancel, or terminate +var result string +err := handle.Get(context.Background(), &result) +if err != nil { + log.Fatalln("Unable to get activity result", err) +} +``` + + +--- + +## 7. Waiting for the result + +Use `ActivityHandle.Get()` to block until the Activity completes and retrieve +its result. This is analogous to calling `Get()` on a `WorkflowRun`. If the +Activity completed successfully the result is deserialized into the provided +pointer; if the Activity failed, the failure is returned as an error. + + +```go +var result string +err = handle.Get(context.Background(), &result) +if err != nil { + log.Fatalln("Activity failed", err) +} +log.Println("Activity result:", result) +``` + + +Or wait for a result by Activity ID with the CLI: + +```bash +temporal activity result --activity-id standalone_activity_helloworld_ActivityID +``` + + +--- + +## 8. Listing Standalone Activities + +Use [`client.ListActivities()`](https://pkg.go.dev/go.temporal.io/sdk/client#Client) +to list Standalone Activity Executions matching a [List Filter](/list-filter) +query. The result contains an iterator that yields `ActivityExecutionInfo` +entries. These APIs return only Standalone Activity Executions — Activities +running inside Workflows are not included. + + +```go +resp, err := c.ListActivities(context.Background(), client.ListActivitiesOptions{ + Query: "TaskQueue = 'standalone-activity-helloworld'", +}) +if err != nil { + log.Fatalln("Unable to list activities", err) +} + +for info, err := range resp.Results { + if err != nil { + log.Fatalln("Error iterating activities", err) + } + log.Printf("ActivityID: %s, Type: %s, Status: %v\n", + info.ActivityID, info.ActivityType, info.Status) +} +``` + + +The `Query` field accepts the same List Filter syntax used for Workflow +Visibility, e.g. `"ActivityType = 'Activity' AND Status = 'Running'"`. + + +CLI equivalent: + +```bash +temporal activity list +``` + + +--- + +## 9. Counting Standalone Activities + +Use [`client.CountActivities()`](https://pkg.go.dev/go.temporal.io/sdk/client#Client) +to count Standalone Activity Executions matching a List Filter query. This +returns the total count of executions (running, completed, failed, etc.) — not +the number of queued tasks. It works the same way as counting Workflow +Executions. + + +```go +resp, err := c.CountActivities(context.Background(), client.CountActivitiesOptions{ + Query: "TaskQueue = 'standalone-activity-helloworld'", +}) +if err != nil { + log.Fatalln("Unable to count activities", err) +} + +log.Println("Total activities:", resp.Count) +``` + + +CLI equivalent: + +```bash +temporal activity count +``` + + +--- + +## 10. Running with Temporal Cloud + +The samples on this page use `envconfig.MustLoadDefaultClientOptions()`, so the +same code works against Temporal Cloud — just configure the connection via +environment variables or a TOML profile. No code changes are needed. + + +For a step-by-step guide on connecting to Temporal Cloud (Namespace creation, +certificate generation, authentication setup), see +[Connect to Temporal Cloud](/develop/go/client/temporal-client#connect-to-temporal-cloud). + + +### Connect with mTLS + +Set these environment variables with values from your Temporal Cloud Namespace +settings: + +``` +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem' +export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key' +``` + + +### Connect with an API key + +Set these environment variables with values from your Temporal Cloud API key +settings: + +``` +export TEMPORAL_ADDRESS=..api.temporal.io:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_API_KEY= +``` + + +Then run the Worker and starter code as shown in the earlier sections. + diff --git a/references/java/standalone-activities.md b/references/java/standalone-activities.md new file mode 100644 index 0000000..db19235 --- /dev/null +++ b/references/java/standalone-activities.md @@ -0,0 +1,267 @@ +# Standalone Activities — Java SDK + +Standalone Activities run independently, without being orchestrated by a Workflow. You start them directly from a Temporal Client using `ActivityClient`. The Activity definition and Worker registration are identical to a Workflow Activity — the same Activity Function can be executed both as a Standalone Activity and as a Workflow Activity with no code changes. + + + +Java SDK support for Standalone Activities is at Pre-release; the underlying feature is in Public Preview. + + + +## 1. Prerequisites + +- Java 8+ +- Temporal Java SDK v1.35.0 or higher +- Temporal CLI v1.7.0 or higher +- Temporal Server v1.31.0 or higher + + + + +Install the CLI with Homebrew: + +```bash +brew install temporal +``` + +Start the local development server (Standalone Activities are enabled by default): + +```bash +temporal server start-dev +``` + + + + +The server listens on `localhost:7233`; the Web UI is at `http://localhost:8233` and exposes a Standalone Activities nav item. + + +### Public Preview limitations + +- Pause, reset, and update options are not supported in Public Preview but scheduled for GA. +- `TerminateExisting` conflict policy / `TerminateIfRunning` reuse policy is not supported yet. + + +## 2. Define your Activity + +An Activity in the Java SDK is an interface annotated with `@ActivityInterface`, with methods annotated with `@ActivityMethod`. The way you define a Standalone Activity is identical to how you define an Activity orchestrated by a Workflow. The same Activity can be executed as a Standalone Activity and as a Workflow Activity. + + +```java +@ActivityInterface +public interface GreetingActivities { + + @ActivityMethod + String composeGreeting(String greeting, String name); +} +``` + + +```java +public class GreetingActivitiesImpl implements GreetingActivities { + + private static final Logger log = LoggerFactory.getLogger(GreetingActivitiesImpl.class); + + @Override + public String composeGreeting(String greeting, String name) { + log.info("Composing greeting..."); + return greeting + ", " + name + "!"; + } +} +``` + + +## 3. Run a Worker with the Activity registered + +Running a Worker for Standalone Activities is the same as running a Worker for Workflow Activities — you create a `WorkerFactory`, register the Activity implementation, and call `factory.start()`. The Worker doesn't need to know whether the Activity will be invoked from a Workflow or as a Standalone Activity. + + +```java +ClientConfigProfile profile = ClientConfigProfile.load(); +WorkflowServiceStubs service = + WorkflowServiceStubs.newServiceStubs(profile.toWorkflowServiceStubsOptions()); + +WorkflowClient client = WorkflowClient.newInstance(service, profile.toWorkflowClientOptions()); +WorkerFactory factory = WorkerFactory.newInstance(client); +Worker worker = factory.newWorker(TASK_QUEUE); +worker.registerActivitiesImplementations(new GreetingActivitiesImpl()); +factory.start(); +System.out.println("Worker running on task queue: " + TASK_QUEUE); +``` + + +`ClientConfigProfile.load()` reads environment variables and TOML configuration files, so the same code works against a local dev server and Temporal Cloud. + + +## 4. Execute a Standalone Activity (wait for result) + +Use `ActivityClient.execute()` to execute a Standalone Activity and block until it completes. Call this from your application code, not from inside a Workflow Definition. This durably enqueues the Standalone Activity in the Temporal Server, waits for it to be executed on your Worker, and then returns the typed result. + + +```java +ActivityClient client = + ActivityClient.newInstance( + service, + ActivityClientOptions.newBuilder().setNamespace(profile.getNamespace()).build()); + +StartActivityOptions options = + StartActivityOptions.newBuilder() + .setId(ACTIVITY_ID) + .setTaskQueue(TASK_QUEUE) + .setStartToCloseTimeout(Duration.ofSeconds(10)) + .build(); + +String result = + client.execute( + GreetingActivities.class, + GreetingActivities::composeGreeting, + options, + "Hello", + "World"); +System.out.println("Activity result: " + result); +``` + + +The typed `execute()` API takes the Activity interface class and an unbound method reference. The SDK uses the method reference to infer the Activity type name and result type at runtime. You can also call Activities by string type name: + + +```java +String result = client.execute("ComposeGreeting", String.class, options, "Hello", "World"); +``` + + +`StartActivityOptions` requires `id`, `taskQueue`, and at least one of `startToCloseTimeout` or `scheduleToCloseTimeout`. + + +## 5. Start a Standalone Activity without waiting for the result + +Starting a Standalone Activity sends a request to the Temporal Server to durably enqueue your Activity job, without waiting for it to be executed by your Worker. Use `ActivityClient.start()` to start a Standalone Activity and get a handle: + + +```java +ActivityHandle handle = + client.start( + GreetingActivities.class, + GreetingActivities::composeGreeting, + options, + "Hello", + "World"); +System.out.println("Started activity ID: " + ACTIVITY_ID); + +// Wait for the result later +String result = handle.getResult(); +System.out.println("Activity result: " + result); +``` + + +### Conflict policy and reuse policy + +Standalone Activities support deduplication via a conflict policy (for example `USE_EXISTING`) and a reuse policy (for example `REJECT_DUPLICATES`). The `TerminateExisting` conflict policy and `TerminateIfRunning` reuse policy are not supported in Public Preview. + + + + + +## 6. Get a handle to an existing Standalone Activity + +Use `client.getHandle()` to create a typed handle to a previously started Standalone Activity: + + +```java +ActivityHandle handle = + client.getHandle("standalone-activity-id", null, String.class); +``` + + +Pass `null` as the run ID to target the latest run of the given activity ID. You can then use the handle to wait for the result, describe, cancel, or terminate the Activity. + + +## 7. Wait for the result of a Standalone Activity + +Calling `client.execute()` is equivalent to calling `client.start()` to durably enqueue the Standalone Activity, then calling `handle.getResult()` to block until the Activity completes and return the result: + + +```java +String result = handle.getResult(); +``` + + +To wait asynchronously without blocking the calling thread, use `handle.getResultAsync()`, which returns a `CompletableFuture`: + + +```java +CompletableFuture future = handle.getResultAsync(); +``` + + +You can also wait for a result by Activity ID with the CLI: + +```bash +./temporal activity result --activity-id standalone-activity-id +``` + + +## 8. List Standalone Activities + +Use `client.listExecutions()` to list Standalone Activity Executions that match a List Filter query. The result is a `Stream` that fetches pages from the server on demand as the stream is consumed. These APIs return only Standalone Activity Executions — Activities running inside Workflows are not included. + + +```java +client + .listExecutions("TaskQueue = '" + TASK_QUEUE + "'") + .forEach( + info -> + System.out.printf( + "ActivityID: %s, Type: %s, Status: %s%n", + info.getActivityId(), info.getActivityType(), info.getStatus())); +``` + + +The query parameter accepts the same List Filter syntax used for Workflow Visibility, for example `ActivityType = 'composeGreeting' AND Status = 'Running'`. + + +## 9. Count Standalone Activities + +Use `client.countExecutions()` to count Standalone Activity Executions matching a List Filter query. This returns the total count of executions (running, completed, failed, etc.) — not the number of queued tasks. It works the same way as counting Workflow Executions. + + +```java +ActivityExecutionCount resp = client.countExecutions("TaskQueue = '" + TASK_QUEUE + "'"); +System.out.println("Total activities: " + resp.getCount()); +resp.getGroups() + .forEach( + group -> + System.out.println("Group " + group.getGroupValues() + ": " + group.getCount())); +``` + + +## 10. Run with Temporal Cloud + +The code samples on this page use `ClientConfigProfile.load()`, so the same code works against Temporal Cloud — just configure the connection via environment variables or a TOML profile. No code changes are needed. + + +### Connect with mTLS + +Set these environment variables with values from your Temporal Cloud Namespace settings: + +``` +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem' +export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key' +``` + + +### Connect with an API key + +Set these environment variables with values from your Temporal Cloud API key settings: + +``` +export TEMPORAL_ADDRESS=..api.temporal.io:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_API_KEY= +``` + + +Then run the Worker and starter code as shown in the earlier sections. + diff --git a/references/python/standalone-activities.md b/references/python/standalone-activities.md new file mode 100644 index 0000000..de23081 --- /dev/null +++ b/references/python/standalone-activities.md @@ -0,0 +1,323 @@ +# Standalone Activities — Python SDK + +Standalone Activities are Activities that run independently, without being orchestrated by a Workflow. Instead of starting an Activity from within a Workflow Definition, you start one directly from a Temporal Client. + + +Temporal Python SDK support for Standalone Activities is at **Public Preview**. + + +**Dual-use:** The way you write the Activity and register it with a Worker is identical to Workflow Activities. The only difference is that you execute a Standalone Activity directly from your Temporal Client. An Activity Function can be executed both as a Standalone Activity and as a Workflow Activity with no code changes. + + + +## Prerequisites + +- **Python 3.9+** +- **Temporal Python SDK** v1.23.0 or higher (`uv add temporalio`) +- **Temporal CLI** v1.7.0 or higher + + +Server requirement: Temporal Server v1.31.0 or higher (Public Preview). + + +Start a local dev server: + +```bash +temporal server start-dev +``` + + +The Web UI is available at `http://localhost:8233`, with a Standalone Activities item in the nav bar. + + +## Write an Activity Function + +An Activity in the Temporal Python SDK is just a normal function with the `@activity.defn` decorator. It can optionally be an `async def`. The way you write a Standalone Activity is identical to how you write an Activity orchestrated by a Workflow. + + +```python +# my_activity.py +from dataclasses import dataclass + +from temporalio import activity + + +@dataclass +class ComposeGreetingInput: + greeting: str + name: str + + +@activity.defn +def compose_greeting(input: ComposeGreetingInput) -> str: + activity.logger.info("Running activity with parameter %s" % input) + return f"{input.greeting}, {input.name}!" +``` + + +## Run a Worker with the Activity registered + +Running a Worker for Standalone Activities is the same as running a Worker for Workflow Activities — you create a Worker, register the Activity, and run the Worker. The Worker doesn't need to know whether the Activity will be invoked from a Workflow or as a Standalone Activity. + + +```python +import asyncio +from concurrent.futures import ThreadPoolExecutor + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig +from temporalio.worker import Worker + +from hello_standalone_activity.my_activity import compose_greeting + + +async def main(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + worker = Worker( + client, + task_queue="my-standalone-activity-task-queue", + activities=[compose_greeting], + activity_executor=ThreadPoolExecutor(5), + ) + print("worker running...", end="", flush=True) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) +``` + + +Run the Worker: + +```bash +uv run hello_standalone_activity/worker.py +``` + + +## Execute a Standalone Activity + +Use `client.execute_activity()` to execute a Standalone Activity. Call this from your application code, not from inside a Workflow Definition. This durably enqueues your Standalone Activity in the Temporal Server, waits for it to be executed on your Worker, and then fetches the result. + + +```python +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + +from hello_standalone_activity.my_activity import ComposeGreetingInput, compose_greeting + + +async def my_application(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + + activity_result = await client.execute_activity( + compose_greeting, + args=[ComposeGreetingInput("Hello", "World")], + id="my-standalone-activity-id", + task_queue="my-standalone-activity-task-queue", + start_to_close_timeout=timedelta(seconds=10), + ) + print(f"Activity result: {activity_result}") + + +if __name__ == "__main__": + asyncio.run(my_application()) +``` + + +The kwargs shown by the doc are: `args`, `id`, `task_queue`, `start_to_close_timeout`. + + +You can also execute a Standalone Activity with the Temporal CLI: + +```bash +temporal activity execute \ + --type compose_greeting \ + --activity-id my-standalone-activity-id \ + --task-queue my-standalone-activity-task-queue \ + --start-to-close-timeout 10s \ + --input '{"greeting": "Hello", "name": "World"}' +``` + + +## Start a Standalone Activity without waiting for the result + +Starting a Standalone Activity means sending a request to the Temporal Server to durably enqueue your Activity job, without waiting for it to be executed by your Worker. Use `client.start_activity()` to start your Standalone Activity and get a handle. + + +```python +activity_handle = await client.start_activity( + compose_greeting, + args=[ComposeGreetingInput("Hello", "World")], + id="my-standalone-activity-id", + task_queue="my-standalone-activity-task-queue", + start_to_close_timeout=timedelta(seconds=10), +) +``` + + +CLI equivalent: + +```bash +temporal activity start \ + --type compose_greeting \ + --activity-id my-standalone-activity-id \ + --task-queue my-standalone-activity-task-queue \ + --start-to-close-timeout 10s \ + --input '{"greeting": "Hello", "name": "World"}' +``` + + + + +## Get a handle to an existing Standalone Activity + +Use `client.get_activity_handle()` to create a handle to a previously started Standalone Activity: + + +```python +activity_handle = client.get_activity_handle( + activity_id="my-standalone-activity-id", + run_id="the-run-id", +) +``` + + +You can use the handle to wait for the result, describe, cancel, or terminate the Activity. + + +## Wait for the result of a Standalone Activity + +Calling `client.execute_activity()` is equivalent to calling `client.start_activity()` to durably enqueue the Standalone Activity, and then calling `await activity_handle.result()` to wait for the activity to be executed and fetch the result. + + +```python +activity_result = await activity_handle.result() +``` + + +CLI equivalent (wait for a result by Activity ID): + +```bash +temporal activity result --activity-id my-standalone-activity-id +``` + + +## List Standalone Activities + +Use `client.list_activities()` to list Standalone Activity Executions that match a List Filter query. The result is an async iterator that yields `ActivityExecution` entries. These APIs return only Standalone Activity Executions — Activities running inside Workflows are not included. + + +```python +import asyncio + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + + +async def my_application(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + + activities = client.list_activities( + query="TaskQueue = 'my-standalone-activity-task-queue'", + ) + + async for info in activities: + print( + f"ActivityID: {info.activity_id}, Type: {info.activity_type}, Status: {info.status}" + ) + + +if __name__ == "__main__": + asyncio.run(my_application()) +``` + + +The `query` parameter accepts the same List Filter syntax used for Workflow Visibility (e.g., `"ActivityType = 'MyActivity' AND Status = 'Running'"`). + + +CLI equivalent: + +```bash +temporal activity list +``` + + +## Count Standalone Activities + +Use `client.count_activities()` to count Standalone Activity Executions that match a List Filter query. This returns the total count of executions (running, completed, failed, etc.) — not the number of queued tasks. It works the same way as counting Workflow Executions. + + +```python +import asyncio + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + + +async def my_application(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + + resp = await client.count_activities( + query="TaskQueue = 'my-standalone-activity-task-queue'", + ) + + print("Total activities:", resp.count) + + for group in resp.groups: + print(f"Group {group.group_values}: {group.count}") + + +if __name__ == "__main__": + asyncio.run(my_application()) +``` + + +CLI equivalent: + +```bash +temporal activity count +``` + + +## Run Standalone Activities with Temporal Cloud + +The code samples on this page use `ClientConfig.load_client_connect_config()`, so the same code works against Temporal Cloud — just configure the connection via environment variables or a TOML profile. No code changes are needed. + + +### Connect with mTLS + +Set these environment variables with values from your Temporal Cloud Namespace settings: + +``` +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem' +export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key' +``` + + +### Connect with an API key + +Set these environment variables with values from your Temporal Cloud API key settings: + +``` +export TEMPORAL_ADDRESS=..api.temporal.io:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_API_KEY= +``` + + +Then run the Worker and starter code as shown in the earlier sections. +