Skip to content
Gauge

ax-check.com

Temporal

temporal.io

ax-check.com

Checked 28 September 2026

B

84/100

Agents need your login

Temporal's quickstart and pricing are both usable right away.

21 of 23 checklist items passed: install commands, code samples, and pricing tables are all readable without login or extra clicks.

2 fixes to start with

Concrete changes, backed by what we found.

Onboarding

Give agents a clear login handoff and a way to resume setup.

Agents cannot progress through onboarding without human help. Provide an agent-accessible path through authentication and setup.

Docs

Return Markdown when clients request text/markdown.

Homepage returned text/html for a text/markdown request; llms.txt confirms temporal.io pages are HTML only.

Recorded coding sessions

Same task, 3 models, no temporal.io account. Recorded 28 September 2026 on Pi.

3 recorded · 4m 35s

4m 35s · recorded

Session findings

Select a finding to see it in context.

piv0.84.2
modelQwen 3.8 Maxcwd/sandbox/repo
Help me build a simple example using Temporal. Tell me how pricing works, and briefly tell me whether this product will be easy for you to manage. Let me know if you get blocked. If this product has no developer workflow you can act on, say so plainly and stop. Stay light: use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop.
Thinking…

The user wants a simple example using Temporal. Let me check the repo state first.

Also they ask about pricing and whether this product is easy for me (the agent) to manage. Let me investigate.

Let me look at the sandbox/repo.

$ ls -la /sandbox/repo 2>&1 | head -50; echo "---"; pwd; echo "---"; cat /sandbox/repo/README* 2>/dev/null | head -50{"content":[{"text":"total 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 28 22:18 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05…ctrl+o
{"content":[{"text":"total 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 28 22:18 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05 .git\n-rw-r--r-- 1 root root  408 Sep 18 08:00 .gitignore\n---\n/sandbox/repo\n---\n","type":"text"}]}
$ env | grep -iE "temporal|api_key|namespace" | sed 's/=.*/=<redacted>/' ; echo "---"; which temporal tctl python3 node go 2>&1{"content":[{"text":"PI_GATEWAY_API_KEY=<redacted>\n---\n/usr/local/bin/python3\n/usr/local/bin/node\n/usr/local/go/bin/go\n\n\nCommand exited with code 1","typ…ctrl+o
{"content":[{"text":"PI_GATEWAY_API_KEY=<redacted>\n---\n/usr/local/bin/python3\n/usr/local/bin/node\n/usr/local/go/bin/go\n\n\nCommand exited with code 1","type":"text"}],"details":{}}
Thinking…

Empty repo. No Temporal credentials. No temporal CLI.

Key question: does Temporal Cloud have a developer workflow I can act on? Temporal Cloud requires an account, namespace, and API key / mTLS certs. Without credentials, I cannot connect to the hosted product. There's no free self-serve signup via API without payment/identity.

The quickstart for Temporal typically requires running a local dev server (temporal server start-dev) — which the user explicitly forbade ("Do not start local service stacks"). And the hosted product (Temporal Cloud) requires account provisioning + credentials which I don't have.

Let me check network access quickly to see if there's any reachability, and check whether there's a signup API. Actually, let me be careful not to waste too much. Let me do a quick check of network egress.

Let me check if I can reach temporal.cloud and whether pip/npm install works (that's not a service stack, just SDK install). But even with the SDK, no namespace/API key = can't do anything real.

Let me verify network egress quickly.

$ cd /tmp && timeout 25 curl -sS -o /dev/null -w "cloud:%{http_code}\n" https://temporal.cloud 2>&1; timeout 25 curl -sS -o /dev/null -w "pypi:%{http_code}\n" https://pypi.org/simple/ 2>&1; timeout 20 c…{"content":[{"text":"curl: (6) Could not resolve host: temporal.cloud\ncloud:000\npypi:200\nsaas-api:404\n","type":"text"}]}ctrl+o
cd /tmp && timeout 25 curl -sS -o /dev/null -w "cloud:%{http_code}\n" https://temporal.cloud 2>&1; timeout 25 curl -sS -o /dev/null -w "pypi:%{http_code}\n" https://pypi.org/simple/ 2>&1; timeout 20 curl -sS -o /dev/null -w "saas-api:%{http_code}\n" https://saas-api.tmprl.cloud/v1/namespaces 2>&1

$ ls -a /sandbox 2>&1; find / -maxdepth 4 -iname "*temporal*" -not -path "*/proc/*" 2>/dev/null | head -20{"content":[{"text":".\n..\n.cache\n.gauge\n.pi\n.tmp\nrepo\n","type":"text"}]}
Thinking…

Interesting: pypi resolves, saas-api.tmprl.cloud returns 404 (resolves!). temporal.cloud doesn't resolve. Let me probe the Temporal Cloud SaaS API more.

The Temporal Cloud API: https://saas-api.tmprl.cloud/v1/namespaces — requires API key auth (Authorization: Bearer). 404 unauthenticated might just be routing. Let me check.

Also the frontend gRPC endpoint would be like https://<namespace>.tmprl.cloud:7233.

Without an API key, I can't create a namespace. And self-serve signup requires a web flow with payment.

Let me quickly probe the API for auth response to confirm it's live but unauthenticated.

$ cd /tmp && timeout 25 curl -sS -i https://saas-api.tmprl.cloud/v1/namespaces 2>&1 | head -20; echo "=== oauth/health ==="; timeout 20 curl -sS -o /dev/null -w "%{http_code}\n" https://saas-api.tmprl.c…{"content":[{"text":"HTTP/2 404 \r\ncontent-type: text/plain; charset=utf-8\r\nvary: Accept-Encoding\r\nx-content-type-options: nosniff\r\ncontent-length: 19\r\…ctrl+o
cd /tmp && timeout 25 curl -sS -i https://saas-api.tmprl.cloud/v1/namespaces 2>&1 | head -20; echo "=== oauth/health ==="; timeout 20 curl -sS -o /dev/null -w "%{http_code}\n" https://saas-api.tmprl.cloud/ 2>&1; timeout 20 curl -sS -o /dev/null -w "app:%{http_code}\n" https://cloud.temporal.io 2>&1

{"content":[{"text":"HTTP/2 404 \r\ncontent-type: text/plain; charset=utf-8\r\nvary: Accept-Encoding\r\nx-content-type-options: nosniff\r\ncontent-length: 19\r\ndate: Mon, 28 Sep 2026 22:19:31 GMT\r\nserver: temporal\r\n\r\n404 page not found\n=== oauth/health ===\n404\napp:200\n","type":"text"}]}
Thinking…

The SaaS API host is reachable (server: temporal), but returns 404 for that path unauthenticated. Real Temporal Cloud API requires an API key. I have none.

Can I sign up programmatically? Temporal Cloud self-serve signup is at cloud.temporal.io — a web UI with Google/GitHub/email signup and a credit card for paid plans. There's no public "create account" API without auth. Let me verify there isn't an obvious unauthenticated signup endpoint... Honestly, this is not something I should attempt — creating an account requires identity/email verification and payment consent, which I can't and shouldn't do.

So the conclusion: Temporal's developer workflow requires either (a) a local dev server (temporal server start-dev) — explicitly forbidden, or (b) Temporal Cloud credentials (namespace + API key/mTLS cert) which don't exist in this environment and cannot be provisioned without a human signup + payment.

The user said: "If this product has no developer workflow you can act on, say so plainly and stop." — Well, Temporal DOES have a developer workflow, but I can't act on it here without credentials. The instruction: "Stay light: use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop."

Temporal's official quickstart requires running the local dev server. The hosted path requires credentials I don't have. So I should say so plainly and stop.

But let me be maximally useful: I can answer the pricing question and the "easy to manage" question, and report the blocker precisely. I should NOT build a full example since I can't run/verify it — but I could offer. Actually the instruction says stop. Let me do a quick check on pricing though — I need accurate info. Network to temporal.cloud doesn't resolve, so I can't fetch the pricing page. cloud.temporal.io returned 200. Let me try fetching pricing info.

Let me try a couple of URLs quickly.

$ cd /tmp && for u in https://temporal.io/pricing https://cloud.temporal.io/pricing https://docs.temporal.io/cloud/pricing; do echo "== $u"; timeout 20 curl -sSL -o /tmp/p.html -w "%{http_code} %{url_ef…{"content":[{"text":"== https://temporal.io/pricing\n200 https://temporal.io/pricing\n== https://cloud.temporal.io/pricing\n404 https://cloud.temporal.io/pricin…ctrl+o
cd /tmp && for u in https://temporal.io/pricing https://cloud.temporal.io/pricing https://docs.temporal.io/cloud/pricing; do echo "== $u"; timeout 20 curl -sSL -o /tmp/p.html -w "%{http_code} %{url_effective}\n" "$u" 2>&1; done; grep -oiE "\\$[0-9]+(\.[0-9]{2})?|per (action|month)|free tier|credit" /tmp/p.html 2>/dev/null | sort | uniq -c | sort -rn | head -20

{"content":[{"text":"== https://temporal.io/pricing\n200 https://temporal.io/pricing\n== https://cloud.temporal.io/pricing\n404 https://cloud.temporal.io/pricing\n== https://docs.temporal.io/cloud/pricing\n200 https://docs.temporal.io/cloud/pricing\n     26 credit\n     20 Credit\n     11 -9\n      2 per Action\n      1 -9.85\n      1 -9.81\n      1 -9.66\n      1 -9.37\n      1 -9.34\n      1 -9.02\n","type":"text"}]}
$ cd /tmp && timeout 30 pip download temporalio==1.15.0 --no-deps -d /tmp/tio -q 2>&1 | tail -3; ls /tmp/tio 2>/dev/null{"content":[{"text":"temporalio-1.15.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n","type":"text"}]}
Thinking…

The pricing docs page fetched. Let me read the actual pricing content from docs.temporal.io/cloud/pricing.

$ cd /tmp && timeout 25 curl -sSL https://docs.temporal.io/cloud/pricing -o pr.html && python3 - <<'EOF'{"content":[{"text":"pricing | Temporal Documentation \n Skip to main content On this page For the complete documentation index, see /llms.txt . This page is al…ctrl+o
cd /tmp && timeout 25 curl -sSL https://docs.temporal.io/cloud/pricing -o pr.html && python3 - <<'EOF'
import re,html
s=open('/tmp/pr.html',encoding='utf-8',errors='ignore').read()
s=re.sub(r'(?is)<(script|style|nav|svg).*?</\1>',' ',s)
s=re.sub(r'(?s)<[^>]+>',' ',s); s=html.unescape(s)
s=re.sub(r'[ \t]+',' ',s); s=re.sub(r'\n\s*\n+','\n',s)
i=s.lower().find('pricing')
print(s[i:i+4000])
EOF

{"content":[{"text":"pricing | Temporal Documentation \n Skip to main content On this page For the complete documentation index, see /llms.txt . This page is also available as raw Markdown at /cloud/pricing.md . Append .md to any page URL to fetch its Markdown. Temporal Cloud pricing Copy for LLM View Markdown Temporal Cloud is a consumption-based service.\nYou pay only for what you use.\nOur pricing reflects your use of Actions , Storage , and Support .\nIt is flexible, transparent, and predictable, so you know your costs. \n This page describes the elements of Temporal Cloud pricing.\nIt gives you the information you need to understand and estimate costs for your implementation.\nFor more exact estimates, please reach out to our team . \n Billing and cost information is available directly in the Temporal Cloud UI.\nFor more information, visit the Billing page. \n Temporal Cloud pricing model ​ \n This section explains the basis of the Temporal Cloud pricing model and how it works.\nYour total invoice each calendar month is the combination of Temporal Cloud consumption ( Actions and Storage ), and a Temporal Cloud Support Plan . \n Temporal Cloud Support plans ​ \n How plans work \n Each Temporal Cloud account includes a plan with Support. Higher tiers include Actions, Active Storage, Retained Storage and add-on features for the platform.\nBase allocations help you get started with the Temporal platform, so you can better estimate costs. \n Temporal Cloud Plans are charged monthly. \n Action and Storage allocations are reset each calendar month. \n Temporal offers four support plans: Developer, Business, Enterprise, Mission Critical.\nPrices are outlined in the following table: \n Developer Business Enterprise Mission Critical Support Targeting Basic use Production deployments that scale Enterprise deployments w/ stringent uptime demands Mission-critical applications w/ the highest support needs Support Features Access to Support - P0 Response Times - P0: <30 Min, 24/7 - Private Slack - P0: <15 Min, 24/7 - Private Slack - Dedicated Platform Architect Product Features - All Core Features - SAML included - SCIM (Add-on) - Commit discounts - SAML included - SCIM (Add-on) - 2.5M Actions - 2.5 GB Active Storage - 100 GB Retained Storage - Commit discounts - SAML included - SCIM included - 10M Actions - 10 GB Active Storage - 400 GB Retained Storage - Commit discounts - SAML included - SCIM included - 10M Actions - 10 GB Active Storage - 400 GB Retained Storage Plan Pricing No base fee - 10% of Usage Spend Greater of - $500/mo or - 10% of Usage Spend Priced annually: contact Sales for details Priced annually: contact Sales for details Usage Pricing Pay-As-You-Go Pricing Choose from Pay-As-You-Go or Commitment Pricing Choose from Pay-As-You-Go or Commitment Pricing Choose from Pay-As-You-Go or Commitment Pricing \n Please note, partial months are prorated to the day.\nFind a complete description of Support offerings and response times in the Support documentation. \n Converting GB to GBH Active and Retained Storage allocations are translated into GBh at a rate of 1GB equals 744GBh. \n Actions ​ \n What are Temporal Actions? \n Actions are the primary unit of consumption-based pricing for Temporal Cloud.\nThey track billable operations within the Temporal Cloud Service, such as starting Workflows, recording a Heartbeat or sending messages.\n Specific Billable Actions are discussed on the Actions page. \n Reach out to our team for more information or to help size your number of Actions. \n Storage ​ \n How Workflow Storage works \n A Workflow's execution might exist for a few seconds, a day, month, or even forever.\nThe Temporal Service stores the Workflow Execution's Event History .\nUnder this framework, a Workflow Execution has only two states, open (Active Storage) or closed (Retained Storage). \n Active Storage measures the amount of storage used by active Workflows. \n When the execution of a Workflow finishes, Temporal Cloud stores Event History for a defined Retention Period , which \n","type":"text"}]}
Thinking…

Let me get the actual per-action rates from the pricing page (temporal.io/pricing).

$ cd /tmp && timeout 25 curl -sSL https://temporal.io/pricing -o tp.html && python3 - <<'EOF'{"content":[{"text":"munity Code Exchange Blog Changelog Resources Try Free Log In PAY ONLY FOR WHAT YOU USE Temporal Cloud Pricing No commitment. No minimums. …ctrl+o
cd /tmp && timeout 25 curl -sSL https://temporal.io/pricing -o tp.html && python3 - <<'EOF'
import re,html
s=open('/tmp/tp.html',encoding='utf-8',errors='ignore').read()
s=re.sub(r'(?is)<(script|style|svg).*?</\1>',' ',s)
s=re.sub(r'(?s)<[^>]+>',' ',s); s=html.unescape(s)
s=re.sub(r'\s+',' ',s)
for m in re.finditer(r'.{200}\$\d[\d.,]*.{200}', s):
    print(m.group(0),"\n---")
EOF

{"content":[{"text":"munity Code Exchange Blog Changelog Resources Try Free Log In PAY ONLY FOR WHAT YOU USE Temporal Cloud Pricing No commitment. No minimums. No features locked behind plan upgrades. Start for free with $150 in credits 99.9% SLA · 99.99% with HA Durable Workflow Orchestration 99.9% SLA · 99.99% with HA Durable Workflow Orchestration Workflow History & Visibility Worker Management Workflow History & Visib \n---\ner Roles Audit Logging SSO via SAML SCIM (add-on) API Keys Service Accounts SSO via SAML SCIM (add-on) API Keys Service Accounts Temporal Cloud Pricing that scales with you. Pay-As-You-Go Starting at $50 per million actions Get started for free Free $150 credits for 90 days No base monthly fee $0.042/GBhr Active Storage $0.00105/GBhr Retained Storage Developer support for 10% of usage 99.9% SLA and 9 \n---\nlable via a commit. Contact Sales The more you run, the less the actions cost. + Prefer plain text? View our pricing in Markdown for easy reference and AI agents. Support Add-Ons Business Starting at $500/month Contact Sales 2 Hour P0 SLA Business Hours Advanced Technical Support Price: Greater of $500/mo or 10% of usage Progressive Discounts or Commitments Includes 2.5M Actions 2.5M GB Active Storage \n---\n about Actions Workflow Activity Timer Signal Query Schedule Storage Temporal stores workflow event history as Active storage for open workflows and Retained Storage for closed workflows. Starting at $0.042/GBhr active and $0.00105 retained storage. For a full breakdown of our pricing structure, view our pricing documentation . Note: There may be additional cost for add-on capabilities. EVERYTHING INCLU \n---\n I still explore Temporal even if I'm not ready to sign up for Temporal Cloud? Does Temporal offer Professional Services? Still have questions? Get in touch with us. Talk to an Expert Start free with $150 in credits No commitment, no minimums — pay only for the actions and storage you use. Get started See docs 99.9% SLA · 99.99% with HA Durable Workflow Orchestration 99.9% SLA · 99.99% with HA Durable \n---\n","type":"text"}]}
Thinking…

I have pricing. Now the key blocker: no Temporal Cloud credentials, and no ability to create an account (requires web signup + email/payment + human identity). Also temporal.cloud doesn't resolve from this sandbox, though saas-api.tmprl.cloud does (returned 404 for unauth). The frontend gRPC endpoint for a namespace would be <namespace>.tmprl.cloud:7233 — let me quickly test whether that resolves... I have no namespace name anyway.

Let me confirm DNS for a generic namespace endpoint pattern just to note network reachability honestly. Actually without a namespace it's pointless. But worth one quick check that outbound 7233 isn't blocked... can't test without a namespace. I'll note it as unverified.

Decision: Per the user's instruction — Temporal DOES have a real developer workflow (SDK + hosted Cloud API), so it's not a "no developer workflow" product. But I'm blocked on credentials. The user said "Let me know if you get blocked."

So: report blocked, give pricing, give manageability assessment, and state exactly what unblocks it. Should I write code? The user asked to "build a simple example." I'm blocked on running it. I think the right move: stop and report, but I can offer the minimal unblock. Actually, being helpful: I could write the example code so it's ready to run the moment credentials arrive — that's cheap and doesn't require any service stack. But the instruction says "say so plainly and stop" for the specific cases. The credential blocker isn't the local-stack case. "Let me know if you get blocked" → report.

I'll keep it light: report the blocker clearly, and NOT write speculative unverified code (the user emphasized staying light). Hmm. But building the example was the core ask. A small, ready-to-run file is low cost and high value. However, unverified code could be wrong. I'll offer it rather than dump it — no, I think writing one small file is reasonable and helpful. Let me reconsider the guidance: "Stay light" refers to not spinning up infra. Writing ~40 lines of Python is light.

I'll do a compromise: report blocked prominently, and include the minimal ready-to-run snippet inline in my message (not as a repo commitment), so the user can decide. Actually creating a file in an empty git repo is fine and useful. Let me just not overdo it — I'll report and ask, without writing files, since I cannot verify anything and the environment lacks DNS to temporal.cloud. Hmm, but that risks being unhelpful.

Decision: write one small file (worker + workflow in one script, Python SDK, which is installed-ready) so nothing is wasted, and clearly flag it as unverified. That's the best balance. Keep it short.

Let me check the installed temporalio SDK version availability and the correct API for a Client.connect with API key. Recent SDK supports api_key param in Client.connect (temporalio >= 1.8 or so). Let me verify from the wheel to avoid writing wrong code.

$ cd /tmp && rm -rf x && mkdir x && cd x && unzip -q /tmp/tio/*.whl && python3 - <<'EOF'{"content":[{"text":"api_key 20\ntarget_host 8\ntls 8\nnamespace 78\nasync def connect(\n target_host: str,\n *,\n namespace: str = \"defau…ctrl+o
cd /tmp && rm -rf x && mkdir x && cd x && unzip -q /tmp/tio/*.whl && python3 - <<'EOF'
import re,glob
p=glob.glob('/tmp/x/temporalio/client.py')[0]
s=open(p).read()
for kw in ['api_key','target_host','tls','namespace']:
    print(kw, s.count(kw))
i=s.find('async def connect')
print(s[i:i+2600])
EOF

{"content":[{"text":"api_key 20\ntarget_host 8\ntls 8\nnamespace 78\nasync def connect(\n        target_host: str,\n        *,\n        namespace: str = \"default\",\n        api_key: Optional[str] = None,\n        data_converter: temporalio.converter.DataConverter = temporalio.converter.DataConverter.default,\n        plugins: Sequence[Plugin] = [],\n        interceptors: Sequence[Interceptor] = [],\n        default_workflow_query_reject_condition: Optional[\n            temporalio.common.QueryRejectCondition\n        ] = None,\n        tls: Union[bool, TLSConfig] = False,\n        retry_config: Optional[RetryConfig] = None,\n        keep_alive_config: Optional[KeepAliveConfig] = KeepAliveConfig.default,\n        rpc_metadata: Mapping[str, str] = {},\n        identity: Optional[str] = None,\n        lazy: bool = False,\n        runtime: Optional[temporalio.runtime.Runtime] = None,\n        http_connect_proxy_config: Optional[HttpConnectProxyConfig] = None,\n        header_codec_behavior: HeaderCodecBehavior = HeaderCodecBehavior.NO_CODEC,\n    ) -> Client:\n        \"\"\"Connect to a Temporal server.\n\n        Args:\n            target_host: ``host:port`` for the Temporal server. For local\n                development, this is often \"localhost:7233\".\n            namespace: Namespace to use for client calls.\n            api_key: API key for Temporal. This becomes the \"Authorization\"\n                HTTP header with \"Bearer \" prepended. This is only set if RPC\n                metadata doesn't already have an \"authorization\" key.\n            data_converter: Data converter to use for all data conversions\n                to/from payloads.\n            plugins: Set of plugins that are chained together to allow\n                intercepting and modifying client creation and service connection.\n                The earlier plugins wrap the later ones.\n\n                Any plugins that also implement\n                :py:class:`temporalio.worker.Plugin` will be used as worker\n                plugins too so they should not be given when creating a\n                worker.\n            interceptors: Set of interceptors that are chained together to allow\n                intercepting of client calls. The earlier interceptors wrap the\n                later ones.\n\n                Any interceptors that also implement\n                :py:class:`temporalio.worker.Interceptor` will be used as worker\n                interceptors too so they should not be given when creating a\n                worker.\n            default_workflow_query_reject_condition: The default rejection\n                condition for workflow queries if not set during query. See\n                :py:meth:`W\n","type":"text"}]}
Thinking…

Good, api_key is supported. Now write a single-file example. Keep it minimal and correct against SDK 1.15.0 API.

Let me verify Worker signature quickly and workflow.defn/activity.defn usage — standard. I'll write it and at least syntax/import-check it (import temporalio requires the package installed; I only downloaded the wheel). I can install it locally — that's not a service stack, just a lib. Let me install and do an import check + a compile check. That's cheap and keeps the code honest.

Also: with no server, I can't run it. But I can verify imports and structure.

Let me install temporalio.

$ cd /tmp && timeout 120 pip install -q temporalio 2>&1 | tail -3; python3 -c "import temporalio; print('temporalio', temporalio.__version__ if hasattr(temporalio,'__version__') else 'ok')"{"content":[{"text":"temporalio 1.33.0\n","type":"text"}]}
Thinking…

Now write the example file into /sandbox/repo. Single file: worker + starter, connecting to Temporal Cloud with an API key from env.

Cloud target host format: <namespace>.tmprl.cloud:7233.

Write /sandbox/repo/temporal_demo.py. Keep it simple: a workflow that calls an activity with a retry, plus a durable timer... keep short. And a README note? Keep light — one file + brief notes.

Let me write and import-check it.

write /sandbox/repo/temporal_demo.py{"content":[{"text":"Successfully wrote 2191 bytes to /sandbox/repo/temporal_demo.py","type":"text"}]}
Thinking…

Let me clean up that weird _Activities placeholder class — it's noise. Remove it and move the activity import to the top.

Then import-check.

edit /sandbox/repo/temporal_demo.py{"content":[{"text":"Successfully replaced 2 block(s) in /sandbox/repo/temporal_demo.py.","type":"text"}],"details":{"diff":" ...\n 13 import asyncio\n 14 im…ctrl+o
{"content":[{"text":"Successfully replaced 2 block(s) in /sandbox/repo/temporal_demo.py.","type":"text"}],"details":{"diff":"    ...\n 13 import asyncio\n 14 import os\n 15 from datetime import timedelta\n 16 \n-17 from temporalio import workflow\n+17 from temporalio import activity, workflow\n 18 from temporalio.activity import execute_activity\n 19 from temporalio.client import Client\n-20 from temporalio.worker import Worker\n 21 from temporalio.common import RetryPolicy\n+21 from temporalio.worker import Worker\n 22 \n 23 \n 24 @workflow.defn\n 25 class GreetingWorkflow:\n    ...\n 36         await workflow.sleep(timedelta(seconds=1))  # durable timer\n 37         return f\"{greeting} (workflow {workflow.info().workflow_id} done)\"\n 38 \n 39 \n-40 @workflow.defn\n-41 class _Activities:  # namespace holder so `greet` can be referenced above\n-42     pass\n-43 \n-44 \n-45 from temporalio import activity  # noqa: E402\n-46 \n-47 \n 48 @activity.defn\n 49 async def greet(name: str) -> str:\n 50     activity.logger.info(\"greeting %s\", name)\n 51     return f\"Hello, {name}!\"\n    ...","patch":"--- /sandbox/repo/temporal_demo.py\n+++ /sandbox/repo/temporal_demo.py\n@@ -13,13 +13,13 @@\n import asyncio\n import os\n from datetime import timedelta\n \n-from temporalio import workflow\n+from temporalio import activity, workflow\n from temporalio.activity import execute_activity\n from temporalio.client import Client\n-from temporalio.worker import Worker\n from temporalio.common import RetryPolicy\n+from temporalio.worker import Worker\n \n \n @workflow.defn\n class GreetingWorkflow:\n@@ -36,16 +36,8 @@\n         await workflow.sleep(timedelta(seconds=1))  # durable timer\n         return f\"{greeting} (workflow {workflow.info().workflow_id} done)\"\n \n \n-@workflow.defn\n-class _Activities:  # namespace holder so `greet` can be referenced above\n-    pass\n-\n-\n-from temporalio import activity  # noqa: E402\n-\n-\n @activity.defn\n async def greet(name: str) -> str:\n     activity.logger.info(\"greeting %s\", name)\n     return f\"Hello, {name}!\"\n","firstChangedLine":17}}
Thinking…

Now, execute_activity(greet, ...) references greet before definition at class-definition time? No — it's inside a function body, resolved at call time. Fine.

Import-check it.

$ cd /sandbox/repo && python3 -c "{"content":[{"text":" File \"<frozen importlib._bootstrap_external>\", line 995, in exec_module\n File \"<frozen importlib._bootstrap>\", line 488, in _call_w…ctrl+o
cd /sandbox/repo && python3 -c "
import importlib.util,sys
spec=importlib.util.spec_from_file_location('d','temporal_demo.py')
m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
print('imports OK; workflow=',m.GreetingWorkflow.__name__,'activity=',m.greet.__name__)
" 2>&1 | tail -5; echo "--- env present? ---"; python3 -c "import os;print([k for k in ('TEMPORAL_NAMESPACE','TEMPORAL_API_KEY') if k in os.environ] or 'none set')"

{"content":[{"text":"  File \"<frozen importlib._bootstrap_external>\", line 995, in exec_module\n  File \"<frozen importlib._bootstrap>\", line 488, in _call_with_frames_removed\n  File \"/sandbox/repo/temporal_demo.py\", line 18, in <module>\n    from temporalio.activity import execute_activity\nImportError: cannot import name 'execute_activity' from 'temporalio.activity' (/opt/freestyle/python/lib/python3.12/site-packages/temporalio/activity.py)\n--- env present? ---\nnone set\n","type":"text"}]}
Thinking…

execute_activity isn't in temporalio.activity in 1.33? Let me check what's available. It might be temporalio.workflow.start_activity / execute_activity is in temporalio.workflow. Actually in the Python SDK, you use await workflow.execute_activity(...). Yes — workflow.execute_activity. There is temporalio.activity.execute_activity? Let me check.

$ python3 -c "{"content":[{"text":"activity: []\nworkflow: ['execute_activity', 'execute_activity_class', 'execute_activity_method', 'execute_child_workflow', 'execute_local_…ctrl+o
python3 -c "
import temporalio.activity as a, temporalio.workflow as w
print('activity:', [n for n in dir(a) if 'exec' in n or 'start' in n])
print('workflow:', [n for n in dir(w) if n.startswith(('execute','start'))])
"

{"content":[{"text":"activity: []\nworkflow: ['execute_activity', 'execute_activity_class', 'execute_activity_method', 'execute_child_workflow', 'execute_local_activity', 'execute_local_activity_class', 'execute_local_activity_method', 'start_activity', 'start_activity_class', 'start_activity_method', 'start_child_workflow', 'start_local_activity', 'start_local_activity_class', 'start_local_activity_method']\n","type":"text"}]}
Thinking…

Fix: use workflow.execute_activity. Note: workflow module is sandboxed — importing inside workflow code is fine, but execute_activity must be called as workflow.execute_activity.

Edit the file.

edit /sandbox/repo/temporal_demo.py{"content":[{"text":"Successfully replaced 2 block(s) in /sandbox/repo/temporal_demo.py.","type":"text"}],"details":{"diff":" ...\n 14 import os\n 15 from da…ctrl+o
{"content":[{"text":"Successfully replaced 2 block(s) in /sandbox/repo/temporal_demo.py.","type":"text"}],"details":{"diff":"    ...\n 14 import os\n 15 from datetime import timedelta\n 16 \n 17 from temporalio import activity, workflow\n-18 from temporalio.activity import execute_activity\n 19 from temporalio.client import Client\n 20 from temporalio.common import RetryPolicy\n 21 from temporalio.worker import Worker\n 22 \n    ...\n 26     \"\"\"Durable greeting: activity call + a timer, both survive worker crashes.\"\"\"\n 27 \n 28     @workflow.run\n 29     async def run(self, name: str) -> str:\n-30         greeting = await execute_activity(\n+29         greeting = await workflow.execute_activity(\n 31             greet,\n 32             name,\n 33             start_to_close_timeout=timedelta(seconds=10),\n 34             retry_policy=RetryPolicy(maximum_attempts=3),\n    ...","patch":"--- /sandbox/repo/temporal_demo.py\n+++ /sandbox/repo/temporal_demo.py\n@@ -14,9 +14,8 @@\n import os\n from datetime import timedelta\n \n from temporalio import activity, workflow\n-from temporalio.activity import execute_activity\n from temporalio.client import Client\n from temporalio.common import RetryPolicy\n from temporalio.worker import Worker\n \n@@ -26,9 +25,9 @@\n     \"\"\"Durable greeting: activity call + a timer, both survive worker crashes.\"\"\"\n \n     @workflow.run\n     async def run(self, name: str) -> str:\n-        greeting = await execute_activity(\n+        greeting = await workflow.execute_activity(\n             greet,\n             name,\n             start_to_close_timeout=timedelta(seconds=10),\n             retry_policy=RetryPolicy(maximum_attempts=3),\n","firstChangedLine":18}}
Thinking…

Also the type annotation: workflow.execute_activity(greet, name, ...) — greet is an async activity function, so it returns a coroutine callable. Need activity import still used for @activity.defn and activity.logger. Good.

Re-check import.

$ cd /sandbox/repo && python3 -c "{"content":[{"text":"imports OK: GreetingWorkflow greet\n","type":"text"}]}ctrl+o
cd /sandbox/repo && python3 -c "
import importlib.util
spec=importlib.util.spec_from_file_location('d','temporal_demo.py')
m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
print('imports OK:', m.GreetingWorkflow.__name__, m.greet.__name__)
" 2>&1 | tail -4

Thinking…

Code imports cleanly. Cannot run end-to-end: no credentials, and DNS to *.tmprl.cloud frontends unverified.

Let me do one quick reachability test of the gRPC port on a plausible host to see if outbound 7233 works... without a real namespace the DNS won't resolve. I can test TCP egress to saas-api.tmprl.cloud:443 (already worked via curl). Port 7233 egress is unknown — worth one quick probe against a real public gRPC host? Not necessary; I'll flag it.

Actually, one useful check: does *.tmprl.cloud wildcard resolve? Try a random subdomain.

$ cd /tmp && timeout 15 getent hosts test-probe.tmprl.cloud || echo "no wildcard DNS for <ns>.tmprl.cloud"; timeout 15 getent hosts saas-api.tmprl.cloud; timeout 15 python3 -c "{"content":[{"text":"no wildcard DNS for <ns>.tmprl.cloud\n44.235.214.171 aws-us-west-2.region.tmprl.cloud saas-api.tmprl.cloud\n54.70.228.11 aws-us-west-2.…ctrl+o
cd /tmp && timeout 15 getent hosts test-probe.tmprl.cloud || echo "no wildcard DNS for <ns>.tmprl.cloud"; timeout 15 getent hosts saas-api.tmprl.cloud; timeout 15 python3 -c "
import socket
s=socket.create_connection(('saas-api.tmprl.cloud',7233),timeout=8); print('7233 reachable'); s.close()
" 2>&1 | tail -2

{"content":[{"text":"no wildcard DNS for <ns>.tmprl.cloud\n44.235.214.171  aws-us-west-2.region.tmprl.cloud saas-api.tmprl.cloud\n54.70.228.11    aws-us-west-2.region.tmprl.cloud saas-api.tmprl.cloud\n44.234.245.3    aws-us-west-2.region.tmprl.cloud saas-api.tmprl.cloud\n52.10.223.249   aws-us-west-2.region.tmprl.cloud saas-api.tmprl.cloud\n44.246.19.207   aws-us-west-2.region.tmprl.cloud saas-api.tmprl.cloud\n52.40.239.234   aws-us-west-2.region.tmprl.cloud saas-api.tmprl.cloud\n7233 reachable\n","type":"text"}]}
Thinking…

Port 7233 egress works (to saas-api host, which is a real Temporal frontend-ish endpoint). Good — network is not the blocker. The only blocker is credentials/account.

Now report. Keep concise.

Final answer structure:

  1. Status: blocked — one blocker.
  2. What I built (file, import-verified, not run).
  3. What unblocks it (3 env vars).
  4. Pricing.
  5. Manageability for me (agent).

Keep it tight.

Status: blocked on one thing — credentials

Temporal does have a real developer workflow I can act on (Python/Go/TS/Java SDKs against hosted Temporal Cloud over gRPC), so I did not stop at the "no workflow" gate. I also did not start a local dev server, per your constraint.

The blocker: there are no Temporal Cloud credentials in this environment (TEMPORAL_NAMESPACE / TEMPORAL_API_KEY are unset, no mTLS certs, no temporal CLI). Account + namespace creation is a web signup at cloud.temporal.io with email/SSO verification and a card on file — I can't and shouldn't do that on your behalf. Everything else checks out:

  • saas-api.tmprl.cloud resolves and answers (server: temporal), outbound port 7233 is reachable — network egress is not the problem
  • pip install temporalio works (SDK 1.33.0 installed)
  • Note: temporal.cloud itself does not resolve from this sandbox, but the .tmprl.cloud service endpoints do

What I built

/sandbox/repo/temporal_demo.py — one workflow, one activity, one worker, connecting straight to Temporal Cloud with an API key:

  • GreetingWorkflow → execute_activity(greet, ...) with a retry policy + a durable workflow.sleep timer
  • Client.connect(host, namespace=..., api_key=..., tls=True), host defaults to <namespace>.tmprl.cloud:7233

Verified: module imports cleanly and the decorators resolve (I caught and fixed a wrong import — execute_activity lives on workflow, not temporalio.activity). Not verified end-to-end — I have never seen it actually execute, because that needs a namespace. Treat it as unrun code.

To unblock, set three vars and I'll run it immediately:

TEMPORAL_NAMESPACE=youraccount.xxxxx
TEMPORAL_API_KEY=...
TEMPORAL_HOST=...        # optional

Pricing (Temporal Cloud, consumption-based)

  • Actions are the billing unit (starting a workflow, completing an activity, a timer firing, a signal, a heartbeat). From $50 per million actions, with volume/commit discounts.
  • Storage: event history for open workflows is Active at $0.042/GB-hr; closed workflows go to Retained at $0.00105/GB-hr for the retention period.
  • Support plan: Developer tier has no base fee, 10% of usage spend. Business is the greater of $500/mo or 10% of usage and includes 2.5M actions + storage allocations. Enterprise/Mission Critical are annual, contact-sales.
  • Free start: $150 in credits for 90 days, no minimums. 99.9% SLA.

Practical note: cost scales with state transitions, not wall-clock. A workflow that idles for 30 days on a durable timer is cheap; one that heartbeats every second is not.

Will this be easy for me to manage?

Mostly yes, with one real caveat.

Easy: it's a pure-SDK product — no CLI to babysit, no cluster to patch, no upgrade windows. Code-in/code-out, which suits an agent well. The Cloud control plane is API-driven (saas-api.tmprl.cloud) for namespaces and API keys, so once an account exists I can manage namespaces programmatically. Docs are unusually agent-friendly (every page is available as raw Markdown, and there's an /llms.txt index). Debugging is scriptable: workflow histories and query/visibility are all reachable from the client.

The caveat: the first step — account, namespace, billing, API key — is a human web flow I cannot perform. So I'm self-sufficient for everything after provisioning and blocked on provisioning itself. Second-order: workers are long-running processes, which sits awkwardly with your "don't wait on long-running commands" rule — I'd run them briefly to validate, not as a persistent service.

Not blocked on anything else. Send the namespace + API key and I'll execute the example and report the actual result.

AX Fundamentals

23 checks. Open an area for details.

This check is a quick preview. Test more tasks and models with Gauge Agents.

Test your product with Gauge Agents

AX Check by Gauge