{
  "id": "python-scripts-workers",
  "name": "Python scripts and AI workers",
  "use_cases": [
    "Reusable automation scripts",
    "Scheduled imports and transformations",
    "Model/tool orchestration workers"
  ],
  "choose_when": [
    "The deliverable is a bounded task or worker rather than a web product",
    "Python SDKs or data libraries materially simplify integrations"
  ],
  "avoid_when": [
    "A one-off script is being expanded into an undocumented product backend",
    "Hard real-time deadlines or a native deployment requirement dominate"
  ],
  "tools": [
    {
      "job": "Packaging and environments",
      "default": "uv + pyproject.toml + committed uv.lock",
      "alternatives": [
        "Preserve an existing maintained packaging workflow"
      ],
      "reason": "One project entry point for dependencies, Python selection, execution and reproducible sync.",
      "limits": "Pin a compatible Python minor and resolve actual package versions at implementation; do not hand-edit uv.lock. Keep environments and caches in a local development workspace.",
      "source_urls": [
        "https://docs.astral.sh/uv/guides/projects/"
      ]
    },
    {
      "job": "Lint and format",
      "default": "Ruff",
      "alternatives": [
        "Preserve existing configured formatter/linter"
      ],
      "reason": "Fast lint and formatting feedback with one configuration.",
      "limits": "Ruff does not replace static typing, tests, authorization checks or runtime validation.",
      "source_urls": [
        "https://docs.astral.sh/ruff/installation/"
      ]
    },
    {
      "job": "Static typing",
      "default": "mypy",
      "alternatives": [
        "ty after project-specific compatibility trial"
      ],
      "reason": "Explicit checks on application boundaries with a conservative established checker.",
      "limits": "Configure strictness and third-party stubs; unchecked Any and untyped functions reduce coverage. No checker performance comparison was run.",
      "source_urls": [
        "https://mypy.readthedocs.io/en/stable/getting_started.html",
        "https://docs.astral.sh/ty/type-checking/"
      ]
    },
    {
      "job": "Testing",
      "default": "pytest with deterministic fake external services and captured fixtures",
      "alternatives": [
        "Integration suites against sandbox services"
      ],
      "reason": "Fast repeatable tests can verify parsing, permissions and retry decisions.",
      "limits": "Add adversarial outputs and partial-failure cases for agents; do not confuse output snapshots with task success.",
      "source_urls": [
        "https://docs.pytest.org/en/stable/getting-started.html"
      ]
    },
    {
      "job": "Validation",
      "default": "Pydantic at configuration, tool-input and model-output boundaries",
      "alternatives": [
        "Standard-library dataclasses for trusted internal values"
      ],
      "reason": "Reject malformed external structures before effects.",
      "limits": "Define strictness intentionally; a validated plan still needs permission and domain checks.",
      "source_urls": [
        "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/"
      ]
    },
    {
      "job": "External I/O",
      "default": "Provider-supported Python SDK or HTTPX with explicit timeouts and bounded concurrency",
      "alternatives": [
        "Standard-library clients for small dependency-free work"
      ],
      "reason": "Centralize transport settings, credentials and test seams.",
      "limits": "Configure total task deadlines as well as network inactivity timeouts; avoid retry storms and duplicated writes; redact credentials from logs.",
      "source_urls": [
        "https://www.python-httpx.org/advanced/timeouts/"
      ]
    },
    {
      "job": "Persistence and migrations",
      "default": "No database for stateless scripts; PostgreSQL + SQLAlchemy/Alembic for shared durable business state",
      "alternatives": [
        "SQLite for one-machine local state"
      ],
      "reason": "Avoid introducing infrastructure before state ownership requires it.",
      "limits": "Files need atomic writes/checkpoints; database state does not automatically resume execution. Review migrations and use task-local sessions.",
      "source_urls": [
        "https://docs.sqlalchemy.org/en/21/orm/session_basics.html",
        "https://alembic.sqlalchemy.org/en/latest/autogenerate.html"
      ]
    },
    {
      "job": "Auth and credentials",
      "default": "Scoped service credentials injected by the execution platform",
      "alternatives": [
        "Delegated user OAuth when required by the integration"
      ],
      "reason": "Workers generally need service authorization rather than user login UI.",
      "limits": "Credential storage/provider is deployment-specific and unselected; keep secrets out of source, fixtures, task payloads and output.",
      "source_urls": [
        "https://docs.astral.sh/uv/guides/integration/docker/",
        "https://www.python-httpx.org/advanced/timeouts/"
      ]
    },
    {
      "job": "Long-running durable agents",
      "default": "Temporal Python SDK when recovery across restarts is required",
      "alternatives": [
        "Celery for independent queued jobs; direct function for bounded work"
      ],
      "reason": "Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits.",
      "limits": "Adds a service and operational cost. Keep external I/O in activities, make side effects idempotent, test replay and cancellation; no end-to-end integration was run.",
      "source_urls": [
        "https://docs.temporal.io/develop/python",
        "https://docs.celeryq.dev/en/stable/userguide/tasks.html"
      ]
    },
    {
      "job": "Execution and deployment",
      "default": "uv-managed package and explicit CLI entry point; separate managed worker process for persistent workers",
      "alternatives": [
        "uv script metadata for a small standalone file",
        "Scheduled container for bounded jobs"
      ],
      "reason": "Make inputs, exit codes and restart behavior reproducible.",
      "limits": "Scheduler/platform is unselected; document non-overlap and checkpoint semantics. Do not add a web server just to run a job.",
      "source_urls": [
        "https://docs.astral.sh/uv/guides/projects/",
        "https://docs.astral.sh/uv/guides/scripts/",
        "https://docs.astral.sh/uv/guides/integration/docker/"
      ]
    },
    {
      "job": "Application logging",
      "default": "Python logging with configured handlers",
      "alternatives": [
        "Preserve an existing compatible project choice"
      ],
      "reason": "Shared standard logging captures application and dependency diagnostics",
      "limits": "Configure logging at entry point, redact credentials and add request/job IDs, duration and failure context. Persist logs on the execution platform; metrics/tracing backend is a separate operational choice.",
      "source_urls": [
        "https://docs.python.org/3/library/logging.html"
      ]
    },
    {
      "job": "Bounded external-call retries",
      "default": "Tenacity only for retryable transient failures",
      "alternatives": [
        "Provider SDK retry policy when sufficient"
      ],
      "reason": "Explicit stop/wait/filter rules support controlled retries",
      "limits": "Install tenacity; set attempt/deadline limits, jitter and exception filters. The bare decorator retries forever without delay; do not stack retries with SDK/worker retries or repeat non-idempotent effects without keys.",
      "source_urls": [
        "https://tenacity.readthedocs.io/en/latest/"
      ]
    },
    {
      "job": "Object storage",
      "default": "Boto3 S3 client when durable objects are required",
      "alternatives": [
        "Preserve an existing compatible project choice"
      ],
      "reason": "Official SDK supports file transfer to S3",
      "limits": "Install boto3 only for S3-backed work; use platform credentials, private keys and bounded transfers. Boto3 is synchronous: keep blocking transfers out of an async event loop; verify alternative provider compatibility.",
      "source_urls": [
        "https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html"
      ]
    },
    {
      "job": "HTTP timeouts",
      "default": "HTTPX client timeouts and connection limits",
      "alternatives": [
        "Preserve an existing compatible project choice"
      ],
      "reason": "Connect/read/write/pool deadlines prevent unbounded remote waits",
      "limits": "Configure shared client timeout and limits; retain overall operation deadline separately because read timeout measures inactivity between chunks. Close clients and redact request logs.",
      "source_urls": [
        "https://www.python-httpx.org/advanced/timeouts/"
      ]
    }
  ],
  "setup_steps": [
    "For maintained work, create a local source project: uv init worker-app; cd worker-app; select/pin compatible Python; uv add httpx pydantic pydantic-settings",
    "uv add --dev ruff mypy pytest; define an importable worker_app package and a pyproject.toml CLI entry point.",
    "Implement explicit inputs, a dry-run or fixture mode, bounded external calls, structured result/error output, and credentials injected by the environment.",
    "For a genuinely standalone file, the alternative is uv init --script task.py then uv add --script task.py httpx pydantic; run via uv run task.py. Promote reused logic into a package.",
    "Only when shared persistent state is required: add sqlalchemy, psycopg and alembic, then configure reviewed migrations. For durable orchestration: uv add temporalio and implement workflows/activities plus a worker connected to a separately provisioned Temporal service.",
    "Package the locked environment for the chosen scheduler or worker platform. Record startup, cancellation, retry, checkpoint and failure-resume behavior; verify fixture execution before live access."
  ],
  "verification_commands": [
    "uv sync --locked",
    "uv run ruff check .",
    "uv run ruff format --check .",
    "uv run mypy src",
    "uv run pytest",
    "uv run python -m compileall -q src"
  ],
  "open_questions": [
    "Which provider SDKs and minimum credential scopes are required?",
    "Are runs bounded, scheduled, queued or long-lived with human waits?",
    "Which effects are safe to retry, and what are run deadlines and cost budgets?",
    "Who owns execution history, alerts, secrets and recovery?"
  ],
  "evidence_status": "documentation-reviewed",
  "sources": [
    {
      "url": "https://docs.astral.sh/uv/guides/projects/",
      "title": "uv projects",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.astral.sh/ruff/installation/",
      "title": "Ruff installation",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://mypy.readthedocs.io/en/stable/getting_started.html",
      "title": "mypy getting started",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.astral.sh/ty/type-checking/",
      "title": "ty type checking",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.pytest.org/en/stable/getting-started.html",
      "title": "pytest getting started",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/",
      "title": "Pydantic strict mode",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://www.python-httpx.org/advanced/timeouts/",
      "title": "HTTPX timeouts",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.sqlalchemy.org/en/21/orm/session_basics.html",
      "title": "SQLAlchemy session basics",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://alembic.sqlalchemy.org/en/latest/autogenerate.html",
      "title": "Alembic autogeneration",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.astral.sh/uv/guides/integration/docker/",
      "title": "uv Docker",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.temporal.io/develop/python",
      "title": "Temporal Python SDK",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
      "title": "Celery tasks",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.astral.sh/uv/guides/scripts/",
      "title": "uv scripts",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.python.org/3/library/logging.html",
      "title": "Python logging",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://tenacity.readthedocs.io/en/latest/",
      "title": "Tenacity documentation",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html",
      "title": "Boto3 uploads",
      "checked_date": "2026-10-10"
    }
  ],
  "title": "Python automation + AI",
  "language": "Python",
  "group": "Tools & automation",
  "kind": [
    "automation"
  ],
  "ui": "none",
  "host": "server",
  "summary": "Scripts, integrations and workers close to the Python data and AI ecosystem.",
  "shape": "uv · Pydantic · HTTPX / provider SDK · pytest",
  "tradeoff": "Persistent workers need an execution platform; model outputs and tool calls need validation.",
  "research_file": "python.json",
  "reviewed": "2026-10-10",
  "best_practices": [
    "Use scoped credentials, explicit timeouts and bounded concurrency for external calls.",
    "Validate model outputs and tool inputs; keep approval boundaries separate from model reasoning.",
    "Test with deterministic fake services and recorded fixtures, including partial failure and replay.",
    "Use a durable workflow engine only when restart recovery is required; make external effects idempotent."
  ],
  "research_freshness": {
    "core_guidance_checked_on": "2026-10-13",
    "sources": [
      "https://docs.astral.sh/uv/guides/projects/",
      "https://docs.astral.sh/uv/guides/scripts/"
    ],
    "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
  },
  "guide_url": "/stacks/python-scripts-workers/",
  "markdown_url": "/stacks/python-scripts-workers/guide.md",
  "json_url": "/stacks/python-scripts-workers/record.json",
  "architecture_and_migration": {
    "id": "python-scripts-workers",
    "version_scope": "Python APIs: TaskGroup/asyncio.timeout require 3.11+; inspected /3 docs currently show 3.15.0. Use a supported minor compatible with selected SDKs and lock it; this does not recommend blindly upgrading to 3.15. Reviewed uv current guides, HTTPX current guides, Celery 5.6.3 task docs and Temporal Python guides. Resolve actual SDK versions in uv.lock before qualification.",
    "operating_model": "Recommendation: a maintained package owns validated inputs, a run/effect ledger, a CLI result contract and a bounded execution loop. A short task may run directly under a scheduler; independent queued jobs fit Celery when broker semantics are qualified; long waits and restart recovery may justify Temporal workflows with external effects in Activities. A prompt, validated model output or log is not proof of a completed effect.",
    "architecture": [
      "Recommendation: separate parsing/validation, pure transformation, provider adapters and effects. Use deterministic fixtures/dry-run for decision logic, scoped injected credentials and stable operation IDs; do not place secrets or raw provider tokens in run payloads.",
      "Recommendation: reuse HTTPX clients with explicit connect/read/write/pool timeouts and connection limits; add a total task deadline and bounded TaskGroup/semaphore or worker-queue execution. Connection limits alone do not bound all queued coroutines.",
      "Recommendation: persist source cursor, input/schema version, effect intent and acknowledged result where restart matters. One-machine SQLite can own local state; shared workers need a chosen shared durable store and lease/ownership model. A checkpoint is not atomically committed with a remote email or payment.",
      "Recommendation: in Temporal, deterministic Workflow code orchestrates Activities, waits and retries; Activities perform provider calls and heartbeat progress. In Celery, configure acknowledgement/redelivery and retry policy to the task's replay semantics. Avoid layering unbounded SDK, decorator and worker retries."
    ],
    "developer_workflow": [
      "Recommendation: inspect existing scheduler, dependencies, input formats and receipts. For maintained local work, uv init --package worker-app creates a package; pin a supported Python minor, add SDK/validation dependencies and commit pyproject.toml plus uv.lock in the maintained source repository.",
      "Recommendation: uv sync --locked, uv run ruff check ., uv run mypy src and uv run pytest require the corresponding dev tools configured/installed. Add fixtures for malformed provider/model output, permission failures, partial effects, ambiguous acknowledgements and resume.",
      "Recommendation: define [project.scripts] for the package CLI and structured JSON results plus explicit success/usage/failure statuses. uv run --locked <entrypoint> uses the locked project; scheduler start, overlap policy, termination and resume command are deployment-owned choices.",
      "Recommendation: for durable orchestration, uv add temporalio and implement Workflow/Activity/Worker components connected to a separately operated Temporal service. Replay representative histories with temporalio.worker.Replayer before workflow changes; test Activity heartbeat/cancellation and time-skipping integration flows.",
      "Recommendation: use uv sync --locked --no-dev inside a reviewed container build, then record the actual entry point, writable state path, credential scopes and dependency/image pins. No scheduler, broker or Temporal integration was executed here."
    ],
    "avoid": [
      "Avoid resuming by rerunning every input: a crash after remote success before checkpoint creates ambiguous effects and needs reconciliation or a provider idempotency key.",
      "Avoid synchronous SDK calls in async execution; use a documented async client or bounded offload, with explicit cancellation limits.",
      "Avoid swallowing CancelledError in TaskGroup work; cooperative cancellation depends on it being propagated after cleanup.",
      "Avoid describing Celery late acknowledgement or a Temporal Workflow as exactly-once external effects. Application/provider idempotency remains necessary.",
      "Avoid importing time/random/network behavior into deterministic Temporal Workflow code; move external I/O into Activities and replay-test changes."
    ],
    "transitions": [
      {
        "capability": "cli",
        "existing_contract": "Capture old script arguments, environment/config precedence, file paths, exit codes and scheduler invocation behavior.",
        "coexistence": "Recommendation: retain the old script as a thin entry point into an importable package while callers transition. Introduce structured output/version fields and an explicit noninteractive/dry-run mode without changing live side effects.",
        "target": "Recommendation: uv package with pyproject.toml entry point, committed uv.lock and supported Python minor; JSON results on stdout, diagnostics on stderr, schema and status policy in the CLI documentation.",
        "benefits": [
          {
            "benefit": "An importable locked package makes repeated automation easier to test and invoke consistently.",
            "prerequisites": "Inputs/entry point/status are defined; compatible Python and SDKs are pinned; scheduler uses the same package build.",
            "tradeoffs": "A lockfile does not fix provider behavior or scheduler overlap; deploy-time environment/credentials remain required."
          }
        ],
        "checks": [
          "Run old scheduler command against the package adapter and compare input/output/status.",
          "Start from a clean locked environment and parse output without progress/log contamination.",
          "Verify dry-run performs zero provider writes and reports the intended actions."
        ],
        "rollback": "Recommendation: restore the previous package/environment and command while preserving versioned run/checkpoint files. Keep the old entry point until every scheduler/caller is migrated.",
        "sources": [
          "https://docs.astral.sh/uv/guides/projects/",
          "https://docs.astral.sh/uv/guides/integration/docker/"
        ],
        "id": "cli-1"
      },
      {
        "capability": "data",
        "existing_contract": "Identify source pagination/cursors, input revisions, item identifiers, partial outputs and acknowledged versus uncertain effects.",
        "coexistence": "Recommendation: introduce a run/effect ledger alongside the old logs and compare reconciliation in fixture mode. Keep one active execution owner; migrate old checkpoints with source-input/version provenance.",
        "target": "Recommendation: transactional SQLite checkpoint/receipt state for one host or an operated shared database for multiple workers. For exported files, validate temporary output then os.replace on the same filesystem; qualify sync/permissions separately.",
        "benefits": [
          {
            "benefit": "Durable progress records allow targeted restart and investigation instead of blind replay.",
            "prerequisites": "Stable item/effect IDs; checkpoint transactions; single writer or tested shared ownership; provider lookup/idempotency for uncertain effects.",
            "tradeoffs": "A file/database commit cannot atomically commit a remote side effect; os.replace atomicity does not establish power-loss durability or cross-filesystem replacement."
          }
        ],
        "checks": [
          "Crash before effect, after remote success and after checkpoint; verify each resume decision.",
          "Resume the same input and prove acknowledged effects are skipped or reconciled.",
          "Interrupt export and verify a complete prior/new artifact; restore ledger from backup and compare cursor ownership."
        ],
        "rollback": "Recommendation: keep the ledger readable by the previous worker or convert it explicitly. Reconcile ambiguous remote outcomes before replay; reverting code cannot unsend a message or reverse a provider write.",
        "sources": [
          "https://docs.python.org/3/library/sqlite3.html",
          "https://docs.python.org/3/library/os.html#os.replace"
        ],
        "id": "data-1"
      },
      {
        "capability": "operations",
        "existing_contract": "Preserve provider rate limits, retry budgets, total run deadline and cleanup/cancellation behavior; SDK inactivity timeout is not a whole-run deadline.",
        "coexistence": "Recommendation: retain sequential mode, add shared HTTPX clients and explicit capacity, and compare fixture results before enabling concurrency. Use a bounded queue for large inputs rather than creating one task for every item.",
        "target": "Recommendation: TaskGroup plus asyncio.timeout for operation lifetime, semaphore/worker limits for admission, HTTPX network timeouts and connection limits. Keep sync SDK work outside the event loop; cancellation of offloaded work needs a separate policy.",
        "benefits": [
          {
            "benefit": "Bounded concurrency and total deadlines prevent unlimited waiting work and reduce abandoned I/O.",
            "prerequisites": "Supported Python 3.11+; every provider adapter honors limits; aggregate retry budget and cancellation cleanup are configured.",
            "tradeoffs": "Read timeout measures inactivity between chunks; cancelling a coroutine does not prove a server write was cancelled; throughput gains are unmeasured."
          }
        ],
        "checks": [
          "Slow streaming chunks beyond the total deadline while below read timeout; the whole operation still stops.",
          "Overload input and verify active plus queued work remain bounded.",
          "Cancel one task during provider I/O; TaskGroup cleanup closes clients and reports any ambiguous write."
        ],
        "rollback": "Recommendation: return to sequential execution with the same receipt IDs and retry budget. Resolve uncertain effects from provider state before retrying; retain operation deadlines.",
        "sources": [
          "https://docs.python.org/3/library/asyncio-task.html",
          "https://docs.python.org/3/library/asyncio-sync.html",
          "https://www.python-httpx.org/advanced/timeouts/",
          "https://www.python-httpx.org/advanced/resource-limits/"
        ],
        "id": "operations-1"
      },
      {
        "capability": "jobs",
        "existing_contract": "Capture independent task payload versions, broker durability, acknowledgement timing, retries, dead-letter handling and scheduler overlap.",
        "coexistence": "Recommendation: keep the old scheduler for unconverted tasks while routing selected task kinds into a qualified Celery queue. One scheduler/consumer owns each kind, and old backlog states remain accounted for.",
        "target": "Recommendation: Celery for independent jobs, with idempotent task bodies, bounded worker concurrency, explicit retry/backoff and intentionally selected acknowledgement/worker-loss settings. Keep existing brokers when their guarantees satisfy the contract.",
        "benefits": [
          {
            "benefit": "A qualified queue permits independent worker restart and retry for bounded jobs.",
            "prerequisites": "Broker persistence/redelivery and payload mapping are tested; task effects are replay-safe; acknowledgement and worker-loss policy are deliberately configured.",
            "tradeoffs": "Late acknowledgement alone does not guarantee redelivery for every child-process termination; Celery worker settings and broker behavior matter; duplicate execution remains possible."
          }
        ],
        "checks": [
          "Terminate the worker during a task and verify actual redelivery for the selected settings.",
          "Lose acknowledgement after an external effect; retries must not duplicate the logical effect.",
          "Drain or transform ready/delayed/retry/failed work before retiring the old scheduler/consumer."
        ],
        "rollback": "Recommendation: stop new producers, retain compatible workers for accepted tasks, and reroute only reconciled unstarted work. A scheduler rollback must not create a second schedule for the same task kind.",
        "sources": [
          "https://docs.celeryq.dev/en/stable/userguide/tasks.html"
        ],
        "id": "jobs-1",
        "option_title": "Independent jobs with Celery"
      },
      {
        "capability": "jobs",
        "existing_contract": "Capture long-lived operation IDs, timer/human-wait behavior, provider effects and history/checkpoint schema before adopting durable orchestration.",
        "coexistence": "Recommendation: keep old workflows running under their existing owner; start only newly routed operation IDs in Temporal. Keep provider calls in Activities and preserve effect IDs across retries. Do not duplicate a live run as a shadow test.",
        "target": "Recommendation: Temporal Python Workflows/Activities with specified timeouts, heartbeats, replay tests and compatible worker deployments. Temporal service/visibility/history retention and operational ownership are prerequisites, not Python package installation side effects.",
        "benefits": [
          {
            "benefit": "Persisted workflow history can resume orchestration across worker restarts and represent long waits.",
            "prerequisites": "Temporal service and workers are operated; Workflow code is deterministic; Activity effects are idempotent/reconcilable; compatible histories pass replay.",
            "tradeoffs": "Adds a service and history/versioning obligations; Activity retries may repeat effects; orchestration recovery is not automatic compensation of external changes."
          }
        ],
        "checks": [
          "Replay representative open and completed histories after code changes; fail promotion on nondeterminism.",
          "Restart workers during timers and Activities; verify orchestration resumes and heartbeat/checkpoint behavior.",
          "Crash after provider success before Activity completion; retry reconciles the stable effect ID."
        ],
        "rollback": "Recommendation: stop routing new IDs to the new workflow version and keep compatible workers servicing existing histories. Replay-test the rollback code; if incompatible, complete/version old executions rather than abandoning their state.",
        "sources": [
          "https://docs.temporal.io/develop/python/workflows/basics",
          "https://docs.temporal.io/develop/python/activities/basics",
          "https://docs.temporal.io/develop/python/activities/timeouts",
          "https://docs.temporal.io/develop/python/best-practices/testing-suite",
          "https://docs.temporal.io/activity-definition"
        ],
        "id": "jobs-2",
        "option_title": "Recoverable multi-step workflows with Temporal"
      }
    ],
    "sources": [
      {
        "url": "https://docs.astral.sh/uv/guides/projects/",
        "title": "uv projects",
        "claim": "Project/package entry points, lockfile-based execution and dependency management are documented."
      },
      {
        "url": "https://docs.astral.sh/uv/guides/integration/docker/",
        "title": "uv Docker",
        "claim": "Locked/no-dev sync and build/runtime environment setup are explicit."
      },
      {
        "url": "https://docs.python.org/3/library/sqlite3.html",
        "title": "Python sqlite3",
        "claim": "Transactions and persisted local state are available; transaction control and concurrency need deliberate configuration."
      },
      {
        "url": "https://docs.python.org/3/library/os.html#os.replace",
        "title": "Python os.replace",
        "claim": "Replacement can be atomic on success and can fail across filesystems; sync/durability is separate."
      },
      {
        "url": "https://docs.python.org/3/library/asyncio-task.html",
        "title": "Python asyncio tasks",
        "claim": "TaskGroup/timeout require 3.11+ and use cancellation; swallowing cancellation breaks structured behavior."
      },
      {
        "url": "https://docs.python.org/3/library/asyncio-sync.html",
        "title": "Python asyncio synchronization",
        "claim": "Semaphore supports bounded task access and is not thread-safe."
      },
      {
        "url": "https://www.python-httpx.org/advanced/timeouts/",
        "title": "HTTPX timeouts",
        "claim": "Connect/read/write/pool timeouts are separate; read timeout concerns waiting for chunks."
      },
      {
        "url": "https://www.python-httpx.org/advanced/resource-limits/",
        "title": "HTTPX resource limits",
        "claim": "Connection and keepalive pool bounds are configurable."
      },
      {
        "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
        "title": "Celery 5.6.3 tasks",
        "claim": "Idempotency, acknowledgements, retries and worker-loss behavior need explicit policy; late ack has exceptions."
      },
      {
        "url": "https://docs.temporal.io/develop/python/workflows/basics",
        "title": "Temporal Python Workflow basics",
        "claim": "Workflow code must respect deterministic/replay constraints."
      },
      {
        "url": "https://docs.temporal.io/develop/python/activities/basics",
        "title": "Temporal Activity basics",
        "claim": "Activity definitions and worker registration place external work outside deterministic Workflow code; idempotency has a separate concept source."
      },
      {
        "url": "https://docs.temporal.io/develop/python/activities/timeouts",
        "title": "Temporal Activity timeouts",
        "claim": "Activity timeouts, retry policies and heartbeats support bounded/recoverable execution."
      },
      {
        "url": "https://docs.temporal.io/develop/python/best-practices/testing-suite",
        "title": "Temporal Python testing",
        "claim": "Replay checks history compatibility; Activity and time-skipping environments support recovery testing."
      },
      {
        "url": "https://docs.temporal.io/activity-definition",
        "title": "Temporal Activity idempotency",
        "claim": "Activities may execute more than once after an unreported completion; completed Activities are not rerun merely by Workflow replay. Provider idempotency keys are enforced by the called service."
      }
    ],
    "reviewed_at": "2026-10-11",
    "evidence": "documentation-reviewed"
  },
  "rewrite_url": "/rewrite/guide.md",
  "migration_contracts_url": "/rewrite/contracts.json",
  "agent_workflow": [
    "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
    "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
    "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
    "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
    "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
  ],
  "selection": {
    "native_ui": false,
    "static_hosting": false,
    "offline_client_candidate": false
  },
  "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
}
