## v1.40.0 - 2026-09-03

### Added

- Added support for tenant-scoped shared concurrency strategies. Declare a `ConcurrencyExpression` with `is_tenant_scoped=True` and a `name`, and reference the same name from the `concurrency` list of tasks in different workflows so they share a single concurrency limit. Tenant-scoped entries can be mixed with ordinary workflow-scoped entries on the same task.
- `ConcurrencyExpression.max_runs` now accepts `int | str`: a string is a CEL expression over task input computing the max runs for each concurrency group, so different groups (e.g. pricing tiers) can have different limits.
- Fixes another durable callback ordering bug which would cause NonDeterminismErrors to be raised on replay in the case where e.g. children were spawned recursively, concurrently.
- Makes workflows register concurrently on `start` to speed up worker boot time

## v1.39.0 - 2026-08-26

### Added

- Added support for `CANCEL_QUEUED_EXCEPT_NEWEST` and `CANCEL_QUEUED_EXCEPT_OLDEST` concurrency strategies.

## v1.38.2 - 2026-08-31

### Changed

- The missing-token configuration error now explains how to run Hatchet embedded for local development, via `Hatchet.from_embedded()`, with a link to the embedded mode docs.

## v1.38.1 - 2026-08-25

### Added

- Adds `Hatchet.stop_embedded()` and `Hatchet.aio_stop_embedded()` to gracefully stop the embedded engine sidecar and wait until it has fully exited, including its bundled Postgres.

## v1.38.0 - 2026-08-24

### Added

- Adds embedded mode: `Hatchet.from_embedded()` runs a full Hatchet engine locally via the `hatchet-embedded-sidecar` binary, downloaded on first use, verified against release checksums on every start, and shut down with your process.

## v1.37.5 - 2026-08-21

### Fixed

- Correctly implements retry behavior on event pushes, which previously were silently ignored by Tenacity

## v1.37.4 - 2026-08-20

### Fixed

- Reverts a broken TLS change from 1.37.3

## v1.37.3 - 2026-08-19

### Fixed

- Correctly passes TLS config through to the API client
- Passes the configured TLS server name (SNI) through to the REST client
- Removes a call to `asyncio.to_thread` that was causing durable callback ordering to end up out-of-ordering, causing non-determinism errors.
- Fixes a possible memory leak with satisfied (pending) durable callbacks not being removed when invocations get stale

## v1.37.2 - 2026-08-12

### Fixed

- Reduces the amount of noise in the logs / Sentry / etc. when action listener reconnects happen and heartbeats fail, as they should auto-recover and can happen on e.g. redeployments.

## v1.37.1 - 2026-08-03

### Fixed

- Fixes a memory leak in the log sender where we'd indefinitely buffer log messages, causing memory to pile up over time.

## v1.37.0 - 2026-07-23

### Changed

- Adds beta `batch_task` methods to both tasks and workflows, allowing for dynamic batching based on either time or batch size.

## v1.36.0 - 2026-07-21

### Added

- Adds support for terminal status-based idempotency keys, which are released when the task holding the key reaches a terminal state (either completed, cancelled, or having failed and exhausted all retries).

## v1.35.1 - 2026-07-20

### Fixed

- Removes a merge conflict that snuck into `main`

## v1.35.0 - 2026-07-16

### Added

- Adds support for defining **idempotency keys** on workflows and standalone tasks, which ensures that they're only run once in a provided time window, based on a CEL expression.

## v1.34.1 - 2026-07-15

### Added

- Adds a `cron_input` option to `workflow`, `task`, and `durable_task` declarations, allowing an input to be supplied to runs triggered by a workflow's `on_crons` schedules. The value is typed against the workflow's input model and serialized onto the workflow version.

## v1.34.0 - 2026-07-09

### Added

- Added `slot_cost` to the `hatchet.task` and `workflow.task` decorators, so a task that needs more memory or CPU can consume more than one worker slot and a worker runs fewer of them at once. On older engines it has no effect. See [Task Slot Cost](https://docs.hatchet.run/v1/advanced-assignment/slot-cost).

## v1.33.18 - 2026-07-08

### Fixed

- Fixes an issue in the action listener which would stop sending heartbeats before all in-flight tasks were completed.

## v1.33.17 - 2026-07-07

### Fixed

- Fixes an issue in the durable event listener where we could hang indefinitely waiting for an ack. Now, we'll time out and allow the task to retry, so it should be able to recover independently.
- Fixes an issue in the durable execution logic where collisions in id + retry count would cause unexpected behavior - fixed by adding the invocation count to the key, when it's provided.
- Fixes an issue in the durable execution logic where a listener reconnect could cause messages to be stuck in the old request queue, causing the listener to hang indefinitely. Now, we will shovel messages from the old queue to the new queue on reconnect, so that they can be processed normally.

## v1.33.16 - 2026-07-05

### Fixed

- Fixes the type of `__name__` in the `DependencyFunc` protocol to be a string instead of a method, which was failing on `ty`.

## v1.33.15 - 2026-07-02

### Added

- Adds `oldest_excluding_retries` to the task stats response

### Changed

- Rolled back required SDK dependencies to the state at `v1.29.5`.

## v1.33.14 - 2026-06-26

### Fixed

- Updates the bulk spawn methods on the internal admin client to dynamically chunk bulk-spawned workflows by the protobuf message size, to avoid hitting gRPC limits on large bulk spawns.

## v1.33.13 - 2026-06-26

### Fixed

- Reworks the internals of event pushes and stream event pubs to use `grpc.aio` directly to limit threading overhead on high-throughput workers.
- Reworks how logs are forwarded to the engine to publish from a thread instead of from an `asyncio.Task` to try to avoid event loop blocking issues.

## v1.33.12 - 2026-06-21

### Fixed

- Fixed a bug where `_aio_memo` crashes on durable task replay when the engine returns `memo_already_existed=True` with an empty payload (`b''`). Proto3 unset bytes fields deserialize to `b''` rather than `None`, slipping past the `is not None` guard and crashing `validate_json(b'')`.

## v1.33.11 - 2026-06-18

### Fixed

- Fixes a bug in the durable event logic where wrapping child spawns `asyncio.gather` causes a race condition with causes a future to hang. Added a lock around various `send_event` calls to synchronize those to prevent the race.

## v1.33.10 - 2026-06-16

### Fixed

- Properly suppresses gRPC fork support log lines on startup when fork support is disabled
- Improves logging around worker startup and shutdown
- Improves retry logic around sending step action events to the engine to better handle transient failures and avoid losing events

## v1.33.9 - 2026-06-14

### Fixed

- Fixes a race condition in the durable event listener where an engine restart can cause the listener to get stuck because of the existence of two separate request queues that are not kept in sync, causing requests to hang indefinitely after being added to the old queue in some cases.

## v1.33.8 - 2026-06-12

### Fixed

- Fixed an issue where errors raised by child tasks spawned inside a durable parent task were not propagated back to the parent. The parent can now catch the child's error and handle it gracefully.

## v1.33.7 - 2026-06-09

### Added

- Added an `individual_run_spans_for_bulk_run` OpenTelemetry config option. When enabled, a child `hatchet.run_workflow` span is created for each item in a bulk run (`run_workflows`), nested under the parent `hatchet.run_workflows` span, with each item's traceparent pointing at its own span. Defaults to `false` to preserve the existing span structure.

### Fixed

- Fixed a bug where synchronous log calls via `asyncio.to_thread` (or other threads) could block workers.

## v1.33.6 - 2026-05-27

### Changed

- Refactored worker graceful shutdown to prevent in-flight tasks from being killed.

## v1.33.5 - 2026-05-12

### Security

- Bump urllib to `2.7.0` to address CVE-2026-44432

## v1.33.4 - 2026-05-08

### Changed

- Fixes a bug where TLS credentials are not passed to the OTLP span exporter.

## v1.33.3 - 2026-04-29

### Changed

- Fixes a bug where passing `wait_for_result=False` when spawning children out of a durable task would not be respected, causing unexpected errors and broken functionality.

## v1.33.2 - 2026-04-22

### Added

- Adds `triggering_event_id` and `triggering_event_key` to the `Context`

## v1.33.1 - 2026-04-21

### Changed

- Adds an optional `label` on durable event waits, which will propagate through to the dashboard

## v1.33.0 - 2026-04-16

### Changed

- Adds `wait` and `before_sleep` parameters to `TenacityConfig` to allow custom retry strategies and retry callbacks.

## v1.32.3 - 2026-04-16

### Changed

- Fixes a couple of internal uses of deprecated methods

## v1.32.2 - 2026-04-15

### Changed

- Fixes a bug where failures sending a completed or failed event from the worker to the engine would fail the task and bypass any retries, even if some were configured on the task

## v1.32.1 - 2026-04-09

### Changed

- Fixes a bug in the shutdown handlers that wouldn't correctly trigger graceful shutdown if only the parent process received a shutdown signal like `SIGTERM`, which might often be the case on e.g. Kubernetes.
- Fixes an issue where we generated protobufs using a more recent grpcio version than the minimum allowed, causing breakages on older versions.

## v1.32.0 - 2026-04-07

### Added

- Adds `scope` and `lookback_window` arguments for the `DurableContext.aio_wait_for_event`, which allows durable tasks to look back in time for events that may have been emitted before the task started.

## v1.31.0 - 2026-04-03

### Added

- Adds `wait_for_result` parameter to `run()`, `aio_run()`, `run_many()`, and `aio_run_many()` on both `Workflow` and `Standalone`. Passing `wait_for_result=False` replaces the `run_no_wait` / `aio_run_no_wait` / `run_many_no_wait` / `aio_run_many_no_wait` methods.
- Exports `WorkerLabel` from the top-level `hatchet_sdk` package, alongside the existing `DesiredWorkerLabel` and `WorkerLabelComparator`.
- Exports `Priority`, `ConcurrencyExpression`, `ConcurrencyLimitStrategy`, `RateLimit`, `RateLimitDuration`, `StickyStrategy`, `SlotType`, `BulkPushEventOptions`, `BulkPushEventWithMetadata`, `PushEventOptions`, and `WorkflowRunTriggerConfig` from the top-level `hatchet_sdk` package.
- Adds a `current_context` property to `Hatchet` as a replacement for the deprecated `get_current_context()` method.

### Changed

- `worker_labels` and `desired_worker_labels` are now stored internally as `list[WorkerLabel]` / `list[DesiredWorkerLabel]` and converted to the protobuf representation at the last moment, rather than eagerly at construction time.
- Adds top-level parameters to all of the `run`, `schedule`, etc. methods to pass options directly, instead of needing to import e.g. `TriggerWorkflowOptions` which wasn't very Pythonic.

### Deprecated

- `run_no_wait()`, `aio_run_no_wait()`, `run_many_no_wait()`, and `aio_run_many_no_wait()` are deprecated in favor of `run(wait_for_result=False)`, `aio_run(wait_for_result=False)`, `run_many(wait_for_result=False)`, and `aio_run_many(wait_for_result=False)` respectively.
- Passing duration parameters (e.g. `schedule_timeout`, `execution_timeout`) as strings is deprecated. Use `timedelta` objects instead.
- Non-async durable tasks are deprecated. Please convert durable task functions to async.
- Passing `desired_worker_labels` as a `dict` to task decorators (`@workflow.task`, `@hatchet.task`, etc.) is deprecated. Use a `list[DesiredWorkerLabel]` with the `key` field set instead.
- Passing `desired_worker_label` as a `dict` to `TriggerWorkflowOptions` is deprecated. Use a `list[DesiredWorkerLabel]` with the `key` field set instead.
- Passing `priority` as an `int` to task and workflow decorators is deprecated. Use `Priority.LOW`, `Priority.MEDIUM`, or `Priority.HIGH` instead.
- Passing `comparator` as an `int` to `DesiredWorkerLabel` is deprecated. Use `WorkerLabelComparator` enum values instead.
- The `debug` parameter on `Hatchet()` is deprecated. Set debug mode via the `HATCHET_CLIENT_DEBUG` environment variable instead.
- The `client` parameter on `Hatchet()` is deprecated and will be removed in v2.0.0.
- `Hatchet.get_current_context()` is deprecated. Use the `Hatchet.current_context` property instead.
- `Context.step_run_id` is deprecated. Use `Context.task_run_id` instead.
- `Context.workflow_input` and `Context.input` are deprecated. Use the input argument passed directly to the task function instead.
- `Context.aio_task_output()` is deprecated. Use `Context.task_output()` instead.
- `Context.done` is deprecated. Use `Context.is_cancelled` instead.
- `Context.fetch_task_run_error()` is deprecated. Use `Context.get_task_run_error()` instead.
- Deprecates a number of internal properties and methods on the `Worker` and `Context` that are not intended for public use. These will be removed in v2.0.0.
- Accessing `ctx.worker` is now deprecated. Use the various properties on the context directly, such as `ctx.worker_id` instead of `ctx.worker.id()`.

## v1.30.0 - 2026-03-30

### Changed

- Adds `mcp_tool` methods to Workflows and Standalone tasks providing compatibility with Claude and OpenAI MCP server tools.

## v1.29.5 - 2026-03-25

### Changed

- Event source info (`hatchet__source_workflow_run_id`, `hatchet__source_step_run_id`) is now injected into event metadata at the `EventClient` level, so cross-workflow trace linking works even without the OTel instrumentor enabled.

## v1.29.3 - 2026-03-23

### Changed

- Fixes `aio_memo` wrapping issue in the OTel instrumentor

## v1.29.2 - 2026-03-17

### Added

- Added `list` and `aio_list` method for Rate Limits Client
- Added `pause`, `unpause`, `aio_pause`, and `aio_unpause` methods for workers client

## v1.29.1 - 2026-03-17

### Changed

- Updates the `DurableTaskRunAckEntry` model to include `workflow_run_external_id` field, to enable spawning children from durable tasks fire-and-forget style.

## v1.29.0 - 2026-03-16

### Added

- Added a `DurableContext.wait_for_event` helper which returns the payload of the awaited event.
- Added an `EvictionPolicy`, which allows durable tasks to be evicted from the worker when idle.

### Changed

- Makes a bunch of internal-facing changes for new durable execution features

## v1.28.2 - 2026-03-12

### Changed

- Fixes a bug where the literal string (`\u0000`) in task output was incorrectly rejected as null unicode.

## v1.28.1 - 2026-03-05

### Changed

- Fixes a bug where lifespans are shut down eagerly before the worker is drained, causing unexpected behavior in still-running tasks.
- Cron expressions now support an optional leading seconds field (6-part expressions), e.g. `30 * * * * *` to trigger at 30 seconds past every minute.

## v1.28.0 - 2026-03-02

### Added

- Adds a `desired_worker_labels` parameter to the `TriggerWorkflowOptions` to allow for dynamically routing task runs to a specific worker at trigger time

### Changed

- Adds support for second-level (six-entry) cron expressions (only supported on new engine versions)

## v1.27.2 - 2026-02-28

### Added

- Adds the `worker_id` to the `Context`

### Changed

- Fixes a bug where failed serialization of task outputs causes the task to hang indefinitely.

## v1.27.1 - 2026-02-27

### Changed

- Updated internal dependencies to address security advisories.

## v1.27.0 - 2026-02-27

### Added

- Adds a `get_current_context` helper on the main `Hatchet` client to allow users to get the current `Context` in tasks (generally in functions called from tasks) without needing to drill the `Context` through function parameters.

### Changed

- Significantly improves serialization performance for task inputs and outputs by using the `dump_json` method on the `TypeAdapter` to do serialization in Rust. Mimics a similar [recent change in FastAPI](https://github.com/fastapi/fastapi/pull/14962).

## v1.26.2 - 2026-02-26

### Added

- Adds `retry_transport_errors` and `retry_transport_methods` to `TenacityConfig` to optionally retry REST transport-level failures for configured HTTP methods (default: `GET`, `DELETE`). Default behavior is unchanged.

### Changed

- Uses a structured `http_method` on `RestTransportError` for determining retry eligibility.

## v1.26.1 - 2026-02-25

### Added

- Adds `retry_429` to `TenacityConfig` (default: `False`) to optionally retry REST HTTP 429 responses.
- Adds `TooManyRequestsException` and maps REST HTTP 429 responses to it.

## v1.26.0 - 2026-02-25

### Fixed

- Fixes dependencies not working when using `type Dependency = Annotated[..., ...]` syntax for annotations on python version 3.12 and 3.13. Adds `typing-inspection` as a dependency.

### Changed

- Changes one function in the python SDK to use `inspect.iscoroutinefunction` instead of `asyncio.iscoroutinefunction` which is deprecated.

## v1.25.2 - 2026-02-19

### Fixed

- Reverts cancellation changes in 1.25.0 that introduced a regression

## v1.25.1 - 2026-02-17

### Fixed

- Fixes internal registration of durable slots

## v1.25.0 - 2026-02-17 **YANKED ON 2/19/26**

### Added

- Adds a `CancellationToken` class for coordinating cancellation across async and sync operations. The token provides both `asyncio.Event` and `threading.Event` primitives, and supports registering child workflow run IDs and callbacks.
- Adds a `CancellationReason` enum with structured reasons for cancellation (`user_requested`, `timeout`, `parent_cancelled`, `workflow_cancelled`, `token_cancelled`).
- Adds a `CancelledError` exception (inherits from `BaseException`, mirroring `asyncio.CancelledError`) for sync code paths.
- Adds `cancellation_grace_period` and `cancellation_warning_threshold` configuration options to `ClientConfig` for controlling cancellation timing behavior.
- Adds `await_with_cancellation` and `race_against_token` utility functions for racing awaitables against cancellation tokens.
- The `Context` now exposes a `cancellation_token` property, allowing tasks to observe and react to cancellation signals directly.

### Changed

- The `Context.exit_flag` is now backed by a `CancellationToken` instead of a plain boolean. The property is maintained for backwards compatibility.
- Durable context `aio_wait_for` now respects the cancellation token, raising `asyncio.CancelledError` if the task is cancelled while waiting.

## v1.24.0 - 2026-02-13

### Added

- Webhooks client for managing incoming webhooks: create, list, get, update, and delete methods for webhooks, so external systems (e.g. GitHub, Stripe) can trigger workflows via HTTP.

## v1.23.4 - 2026-02-13

### Changed

- Fixes cases where raising exception classes or exceptions with no message would cause the whole error including stack trace to be converted to an empty string.
- When an error is raised because a workflow has no tasks it now includes the workflows name.

## v1.23.3 - 2026-02-12

### Added

- Adds type-hinted `Standalone.output_validator` and `Standalone.output_validator_type` properties to support easier type-safety and match the `input_validator` property pattern on `BaseWorkflow`.
- Adds type-hinted `Task.output_validator` and `Task.output_validator_type` properties to support easier type-safety and match the patterns on `BaseWorkflow/Standalone`.
- Adds parameterized unit tests documenting current retry behavior of the Python SDK’s tenacity retry predicate for REST and gRPC errors.

## v1.23.2 - 2026-02-11

### Changed

- Improves error handling for REST transport-level failures by raising typed exceptions for timeouts, connection, TLS, and protocol errors while preserving existing diagnostics.

## v1.23.1 - 2026-02-10

### Changed

- Fixes a bug introduced in v1.21.0 where the `BaseWorkflow.input_validator` class property became incorrectly typed. Now separate properties are available for the type adapter and the underlying type.

## v1.23.0 - 2026-02-05

### Internal Only

- Updated gRPC/REST contract field names to snake_case for consistency across SDKs.

## v1.22.16 - 2026-02-05

### Changed

- Changes the python SDK to use `inspect.iscoroutinefunction` instead of `asyncio.iscoroutinefunction` which is deprecated.
- Improves error diagnostics for transport-level failures in the REST client, such as SSL, connection, and timeout errors, by surfacing additional context.

## v1.22.15 - 2026-02-02

### Added

- Adds `task_name` and `workflow_name` properties to the `Context` and `DurableContext` classes to allow tasks and lifespans to access their own names.

### Changed

- Fixes a bug to allow `ContextVars` to be used in lifespans
- Improves worker shutdown + cleanup logic to avoid leaking semaphores in the action listener process.

## v1.22.14 - 2026-01-31

### Changed

- Allows `None` to be sent from `send_step_action_event` to help limit an internal error on the engine.

## v1.22.13 - 2026-01-29

### Added

- Sends the `task_retry_count` when sending logs to the engine to enable filtering on the frontend.

## v1.22.12 - 2026-01-28

### Added

- Adds a `default_additional_metadata` to the `hatchet.workflow`, `hatchet.task`, and `hatchet.durable_task` methods, which allows you to declaratively provide additional metadata that will be attached to each run of the workflow or task by default.

### Internal Only

- Sends a JSON schema to the engine on workflow registration in order to power autocomplete for triggering workflows from the dashboard.

## v1.22.11 - 2026-01-27

### Changed

- Improves handling of cancellations for tasks to limit how often tasks receive a cancellation but then are marked as succeeded anyways.

## v1.22.10 - 2026-01-26

### Added

- `HATCHET_CLIENT_WORKER_HEALTHCHECK_BIND_ADDRESS` now allows configuring the bind address for the worker healthcheck server (default: `0.0.0.0`)

## v1.22.9 - 2026-01-26

### Added

- Adds missing `unwrap` for `schedule_workflow` in OpenTelemetry instrumentor.

## v1.22.8 - 2026-01-20

### Added

- Adds `HATCHET_CLIENT_WORKER_HEALTHCHECK_EVENT_LOOP_BLOCK_THRESHOLD_SECONDS` to configure when the worker healthcheck becomes unhealthy if the listener process event loop is blocked / task runs are not starting promptly.

### Removed

- Removes a bunch of Poetry scripts that were mostly used for local development and are not necessary for end users of the SDK.

### Changed

- The worker healthcheck server (`/health`, `/metrics`) now runs in the spawned action-listener process (non-durable preferred; durable fallback), instead of the main worker process.
- The worker `/health` endpoint now checks for listener connection status and aio event loop health.
- The worker `/metrics` endpoint now exposes listener-focused metrics like `hatchet_worker_listener_health_<worker_name>` and `hatchet_worker_event_loop_lag_seconds_<worker_name>`.

## v1.22.7 - 2026-01-19

### Added

- Adds `is_in_hatchet_serialization_context` function which can be used on a Pydantic `ValidationInfo.context` to determine if the validation/serialization is occurring as a part of Hatchet deserializing task input or serializing task outputs.

## v1.22.6 - 2026-01-14

### Added

- Adds `max_attempts: int` (retries + 1) to the Context

## v1.22.5 - 2026-01-09

### Added

- Adds an `additional_metadata` field to the `get_details` response.

## v1.22.4 - 2026-01-08

### Added

- Adds a `get_details` method to the runs client

## v1.22.3 - 2026-01-07

### Changed

- Fixes an issue with the type signature for chained dependencies
- Truncates log messages to 10,000 characters to avoid issues with overly large logs.

## v1.22.2 - 2025-12-31

### Added

- Crons can now be provided by alias, e.g. `@daily`

### Changed

- Failed workflow logs are only reported at the `exception` level either on the last retry attempt or if the task is marked as `non_retryable`, to avoid spamming e.g. Sentry with exceptions.

## v1.22.1 - 2025-12-30

### Changed

- Regenerates some API signatures after deprecating many v0 routes.

## v1.22.0 - 2025-12-26

### Added

- Dependencies are now chainable, so one dependency can rely on an upstream one, similar to in FastAPI.
- Dependencies can now be both functions (sync and async) and context managers (sync and async) to allow for cleaning up things like database connections, etc.
- The `ClientConfig` has a new `Tenacity` object, which allows for specifying retry config.
- Concurrency limits can now be specified as integers, which will provide behavior equivalent to setting a constant key with a `GROUP_ROUND_ROBIN` strategy.

### Changed

- Improves the errors raised out of the sync `result` method on the `WorkflowRunRef` to be more in line with the async version, raising a `FailedTaskRunExceptionGroup` that contains all of the task run errors instead of just the first one.

### Internal

- Replaces manual validation logic with Pydantic's `TypeAdapter` for improved correctness and flexibility.

## v1.21.8 - 2025-12-26

### Changed

- Fixes a bug where static rate limits reset their own values to zero on task registration.

## v1.21.7 - 2025-12-15

### Added

- Adds a `get` method to the event client

## v1.21.6 - 2025-12-11

### Added

- Adds `get_task_stats` and `aio_get_task_stats` methods to the `metrics` feature client.

### Changed

- Regenerates the REST and gRPC clients to pick up latest API changes.

## v1.21.5 - 2025-12-06

### Changed

- Task outputs that fail to serialize to JSON will now raise an `IllegalTaskOutputError` instead of being stringified. This pulls errors from the engine upstream to the SDK, and will allow users to catch and handle these errors more easily.

## v1.21.4 - 2025-12-05

### Added

- Adds support for dynamic rate limits using CEL expressions (strings) for the `limit` parameter.

### Changed

- Fixes a serialization error caused by Pydantic sometimes being unable to encode bytes, reported here: https://github.com/hatchet-dev/hatchet/issues/2601
- Fixes a bug where string-based CEL expressions for `limit` were rejected due to the validation logic.

## v1.21.3 - 2025-11-26

### Added

- Adds GZIP compression for gRPC communication between the SDK and the Hatchet engine to reduce bandwidth usage.

## v1.21.2 - 2025-11-13

### Added

- Adds an OTel option to allow you to include the action name in the root span name for task runs.

### Changed

- Span kinds (e.g. producer, consumer) have been added to OpenTelemetry spans created by the SDK to better reflect their roles.

## v1.21.1 - 2025-11-08

### Changed

- The `list` methods for the logs client now allow for pagination via the `limit`, `since`, and `until` params.

## v1.21.0 - 2025-10-31

### Added

- Adds support for dataclasses as input validators for workflows (and tasks), and also as output validators for tasks.

### Changed

- Fixes a bug where an exception in a lifespan would cause the lifespan to hang indefinitely.

## v1.20.2 - 2025-10-15

### Added

- Adds a `include_payloads` parameter to the `list` methods on the runs client (defaults to true, so no change in behavior).

## v1.20.1 - 2025-10-14

### Added

- Adds wrapper methods for bulk cancelling / replaying large numbers of runs with pagination.

## v1.20.0 - 2025-10-3

### Removed

- Removes all references to `get_group_key_*` which is no longer available in V1
- Removes all checks + references to V0

## v1.19.0 - 2025-09-24

### Removed

- Removed the deprecated `v0` client and all related code.
- Removed unused dependencies.

## v1.18.1 - 2025-08-26

### Changed

- Fixes an install issue caused by a misnamed optional dependency.

## v1.18.0 - 2025-08-26

### Added

- Adds a `stubs` client on the main `Hatchet` client, which allows for creating typed stub tasks and workflows. These are intended to be used for triggering workflows that are registered on other workers in either other services or other languages.
- Adds a config option `force_shutdown_on_shutdown_signal` which allows users to forcefully terminate all processes when a shutdown signal is received instead of waiting for them to exit gracefully.

## v1.17.2 - 2025-08-20

### Added

- Adds back an optional `cel-python` dependency for v0 compatibility, allowing users to use the v0 client with the v0-compatible features in the SDK.
- Adds `dependencies` to the `mock_run` methods on the `Standalone`.
- Removes `aiostream` dependency that was unused.
- Removes `aiohttp-retry` dependency that was unused.

## v1.17.1 - 2025-08-18

### Added

- Adds a `HATCHET_CLIENT_LOG_QUEUE_SIZE` environment variable to configure the size of the log queue used for capturing logs and forwarding them to Hatchet

## v1.17.0 - 2025-08-12

### Added

- Adds support for dependency injection in tasks via the `Depends` class.
- Deprecated `fetch_task_run_error` in favor of `get_task_run_error`, which returns a `TaskRunError` object instead of a string. This allows for better error handling and debugging.

### Changed

- Uses `logger.exception` in place of `logger.error` in the action runner to improve (e.g.) Sentry error reporting
- Extends the `TaskRunError` to include the `task_run_external_id`, which is useful for debugging and tracing errors in task runs.
- Fixes an issue with logging which allows log levels to be respected over the API.

### Removed

- Removes the `cel-python` dependency

## v1.16.5 - 2025-08-07

### Changed

- Relaxes constraint on Prometheus dependency

## v1.16.4 - 2025-07-28

### Added

- Adds a new config option `grpc_enable_fork_support` to allow users to enable or disable gRPC fork support. This is useful for environments where gRPC fork support is not needed or causes issues. Previously was set to `False` by default, which would cause issues with e.g. Gunicorn setups. Can also be set with the `HATCHET_CLIENT_GRPC_ENABLE_FORK_SUPPORT` environment variable.

### Changed

- Changes `ValidTaskReturnType` to allow `Mapping[str, Any]` instead of `dict[str, Any]` to allow for more flexible return types in tasks, including using `TypedDict`.

## v1.16.3 - 2025-07-23

### Added

- Adds support for filters and formatters in the logger that's passed to the Hatchet client.
- Adds a flag to disable log capture.

### Changed

- Fixes a bug in `aio_sleep_for` and the `SleepCondition` that did not allow duplicate sleeps to be awaited correctly.
- Stops retrying gRPC requests on 4XX failures, since retrying won't help

## v1.16.2 - 2025-07-22

### Added

- Adds an `input_validator` property to `BaseWorkflow` which returns a typechecker-aware version of the validator class.

## v1.16.1 - 2025-07-18

### Added

- Adds a `CEL` feature client for debugging CEL expressions

## v1.16.0 - 2025-07-17

### Added

- Adds new methods for unit testing tasks and standalones, called `mock_run` and `aio_mock_run`, which allow you to run tasks and standalones in a mocked environment without needing to start a worker or connect to the engine.
- Improves exception logs throughout the SDK to provide more context for what went wrong when an exception is thrown.
- Adds `create_run_ref`, `get_result`, and `aio_get_result` methods to the `Standalone` class, to allow for getting typed results of a run more easily.
- Adds `return_exceptions` option to the `run_many` and `aio_run_many` methods to be more similar to e.g. `asyncio.gather`. If `True`, exceptions will be returned as part of the results instead of raising them.

### Changed

- Correctly propagates additional metadata through the various `run` methods to spawned children.

## v1.15.3 - 2025-07-14

### Changed

- `remove_null_unicode_character` now accepts any type of data, not just strings, dictionaries, lists, and tuples. If the data is not one of these types, it's returned as-is.

## v1.15.2 - 2025-07-12

### Changed

- Fixes an issue in `capture_logs` where the `log` call was blocking the event loop.

## v1.15.1 - 2025-07-11

### Added

- Correctly sends SDK info to the engine when a worker is created

## v1.15.0 - 2025-07-10

### Added

- The `Metrics` client now includes a method to scrape Prometheus metrics from the tenant.

### Changed

- The `Metrics` client's `get_task_metrics` and `get_queue_metrics` now return better-shaped, correctly-fetched data from the API.

## v1.14.4 - 2025-07-09

### Added

- Adds `delete` and `aio_delete` methods to the workflows feature client and the corresponding `Workflow` and `Standalone` classes, allowing for deleting workflows and standalone tasks.

## v1.14.3 - 2025-07-07

### Added

- Adds `remove_null_unicode_character` utility function to remove null unicode characters from data structures.

### Changed

- Task outputs that contain a null unicode character (\u0000) will now throw an exception instead of being serialized.
- OpenTelemetry instrumentor now correctly reports exceptions raised in tasks to the OTel collector.

## v1.14.2 - 2025-07-03

### Added

- The `Runs` client now has `list_with_pagination` and `aio_list_with_pagination` methods that allow for listing workflow runs with internal pagination. The wrappers on the `Standalone` and `Workflow` classes have been updated to use these methods.
- Added retries with backoff to all of the REST API wrapper methods on the feature clients.

## v1.14.1 - 2025-07-03

### Changed

- `DurableContext.aio_wait_for` can now accept an or group, in addition to sleep and event conditions.

## v1.14.0 - 2025-06-25

### Added

- Adds an `IllegalTaskOutputError` that handles cases where tasks return invalid outputs.
- Logs `NonRetryableException` as an info-level log so it doesn't get picked up by Sentry and similar tools.

### Changed

- Exports `NonRetryableException` at the top level
- Fixes an issue with the `status` field throwing a Pydantic error when calling `worker.get`
- Fixes an issue with duplicate protobufs if you try to import both the v1 and v0 clients.

## v1.13.0 - 2025-06-25

### Added

- Documentation for the `Context` classes
- Allows for a worker to be terminated after a certain number of tasks by providing the `terminate_worker_after_num_tasks` config option

### Changed

- Adds a number of helpful Ruff linting rules
- `DedupeViolationErr` is now `DedupeViolationError`
- Fixed events documentation to correctly have a skipped run example.
- Changed default arguments to many methods from mutable defaults like `[]` to None
- Changes `JSONSerializableMapping` from `Mapping` to `dict`
- Handles some potential bugs related to `asyncio` tasks being garbage collected.
- Improves exception printing with an `ExceptionGroup` implementation
- Fixes a bug with namespacing of user event conditions where the namespace was not respected so the task waiting for it would hang
- Fixes a memory leak in streaming and logging, and fixes some issues with log capture.

## v1.12.3 - 2025-06-25

### Changed

- Fixes a namespacing-related but in the `workflow.id` property that incorrectly (and inconsistently) returned incorrect IDs for namespaced workflows.

## v1.12.2 - 2025-06-17

### Changed

- Fixes a security vulnerability by bumping the `protobuf` library

## v1.12.1 - 2025-06-13

### Added

- Adds corresponding SDK changes from API changes to events (additional parameters to filter events by, additional data returned)

## v1.12.0 - 2025-06-06

### Added

- Adds a warning on client init if the SDK version is not compatible with the tenant (engine) version.
- Adds a `default_filters` parameter to the `Hatchet.workflow` and `Hatchet.task` methods to allow you to declaratively provide a list of filters that will be applied to the workflow by default when events are pushed.
- Adds `get_status` and `aio_get_status` methods to the `Runs` feature client, which return a workflow run's status by its ID.
- Adds a `update` methods to the `Filters` feature client.

### Changed

- Allows the `concurrency` parameter to tasks to be a `list`.
- Fixes an internal bug with duplicate concurrency expressions being set when using `Hatchet.task`.
- Modifies existing `datetime` handling to use UTC timestamps everywhere.

## v1.11.1 - 2025-06-05

### Changed

- Fixes a couple of blocking calls buried in the admin client causing loop blockages on child spawning

## v1.11.0 - 2025-05-29

### Changed

- Significant improvements to the OpenTelemetry instrumentor, including:
  - Traceparents are automatically propagated through the metadata now so the client does not need to provide them manually.
  - Added a handful of attributes to the `run_workflow`, `push_event`, etc. spans, such as the workflow being run / event being pushed, the metadata, and so on. Ignoring
  - Added tracing for workflow scheduling

## v1.10.2 - 2025-05-19

### Changed

- Fixing an issue with the spawn index being set at the `workflow_run_id` level and not the `(workflow_run_id, retry_count)` level, causing children to be spawned multiple times on retry.

## v1.10.1 - 2025-05-16

### Added

- Adds an `otel` item to the `ClientConfig` and a `excluded_attributes: list[OTelAttribute]` there to allow users to exclude certain attributes from being sent to the OpenTelemetry collector.

## v1.10.0 - 2025-05-16

### Added

- The main `Hatchet` client now has a `filters` attribute (a `Filters` client) which wraps basic CRUD operations for managing filters.
- Events can now be pushed with a `priority` attribute, which sets the priority of the runs triggered by the event.
- There are new `list` and `aio_list` methods for the `Events` client, which allow listing events.
- Workflow runs can now be filtered by `triggering_event_external_id`, to allow for seeing runs triggered by a specific event.
- There is now an `id` property on all `Workflow` objects (`Workflow` created by `hatchet.workflow` and `Standalone` created by `hatchet.task`) that returns the ID (UUID) of the workflow.
- Events can now be pushed with a `scope` parameter, which is required for using filters to narrow down the filters to consider applying when triggering workflows from the event.

### Changed

- The `name` parameter to `hatchet.task` and `hatchet.durable_task` is now optional. If not provided, the task name will be the same as the function name.
