archastro.platform.channels.api_tasks_channel

  1# Copyright (c) 2026 ArchAstro Inc. Licensed under the MIT License.
  2# This file is auto-generated by @archastro/sdk-generator. Do not edit.
  3# Content hash: 923456011b8a
  4
  5from collections.abc import Callable
  6from datetime import datetime
  7from typing import TYPE_CHECKING, Any, Required, TypedDict
  8
  9if TYPE_CHECKING:
 10    from archastro.phx_channel.socket import Socket
 11
 12
 13class TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture(TypedDict, total=False):
 14    file: str | None
 15    "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file."
 16    height: int | None
 17    "Height of the image in pixels. `null` if not known."
 18    media: str | None
 19    "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity."
 20    mime_type: str | None
 21    'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.'
 22    refresh_url: str | None
 23    "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing."
 24    url: str | None
 25    "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires."
 26    width: int | None
 27    "Width of the image in pixels. `null` if not known."
 28
 29
 30class TasksUpdatedPayloadTasksItemCreatedByActor(TypedDict, total=False):
 31    alias: str | None
 32    "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured."
 33    id: str | None
 34    'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.'
 35    name: str | None
 36    "Display name of the actor shown in the UI. `null` if no name is set."
 37    profile_picture: TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture | None
 38    "Profile picture for the actor. `null` if the actor has no profile picture."
 39
 40
 41class TasksUpdatedPayloadTasksItemCurrentLease(TypedDict):
 42    expires_at: datetime
 43    "Server-calculated lease expiry in ISO 8601 format."
 44    harness: str
 45    "Bounded harness identifier for the coding session."
 46    session_name: str
 47    "Display name supplied by the coding session that holds the lease."
 48
 49
 50class TasksUpdatedPayloadTasksItemOwnerActorProfilePicture(TypedDict, total=False):
 51    file: str | None
 52    "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file."
 53    height: int | None
 54    "Height of the image in pixels. `null` if not known."
 55    media: str | None
 56    "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity."
 57    mime_type: str | None
 58    'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.'
 59    refresh_url: str | None
 60    "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing."
 61    url: str | None
 62    "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires."
 63    width: int | None
 64    "Width of the image in pixels. `null` if not known."
 65
 66
 67class TasksUpdatedPayloadTasksItemOwnerActor(TypedDict, total=False):
 68    alias: str | None
 69    "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured."
 70    id: str | None
 71    'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.'
 72    name: str | None
 73    "Display name of the actor shown in the UI. `null` if no name is set."
 74    profile_picture: TasksUpdatedPayloadTasksItemOwnerActorProfilePicture | None
 75    "Profile picture for the actor. `null` if the actor has no profile picture."
 76
 77
 78class TasksUpdatedPayloadTasksItem(TypedDict, total=False):
 79    agent: str | None
 80    "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user."
 81    aggregate_version: int | None
 82    "Event-stream version for optimistic update fencing. Pass this value as `expected_version` on an update to reject concurrent writes."
 83    blocked_by_count: int | None
 84    "Number of readable tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind."
 85    closed_at: datetime | None
 86    "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open."
 87    comments_count: int | None
 88    "Total number of comments posted on this task."
 89    created_at: datetime | None
 90    "When the task was created (ISO 8601)."
 91    created_by_actor: TasksUpdatedPayloadTasksItemCreatedByActor | None
 92    "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted)."
 93    created_by_agent: str | None
 94    "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted."
 95    created_by_user: str | None
 96    "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted."
 97    current_lease: TasksUpdatedPayloadTasksItemCurrentLease | None
 98    "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included."
 99    description: str | None
100    "Long-form description or notes for the task. `null` if no description has been provided."
101    due_date: datetime | None
102    "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set."
103    epic: str | None
104    "Free-form grouping label. `null` when the task is not in an epic."
105    id: Required[str]
106    "Task ID (`tsk_...`)."
107    is_blocked: bool | None
108    "`true` while at least one blocking task is not yet done. Informational only - a blocked task can still change status - and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on reads, including mutation responses."
109    is_stalled: bool | None
110    "True exactly when status is in_progress and the task has no lease or its lease expiry is in the past. Derived at read time from status and lease expiry, including on unannotated reads."
111    links: dict[str, Any] | None
112    "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set."
113    metadata: dict[str, Any] | None
114    "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set."
115    name: Required[str]
116    "Human-readable title of the task."
117    org: str | None
118    "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context."
119    owner_actor: TasksUpdatedPayloadTasksItemOwnerActor | None
120    "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted)."
121    owner_agent: str | None
122    "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted."
123    owner_user: str | None
124    "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted."
125    parent: str | None
126    "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks or when the parent is not readable. Subtasks nest exactly one level."
127    priority: int | None
128    "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set."
129    project_id: str | None
130    "Optional project ID (`prj_...`). Membership does not change task visibility."
131    sandbox: str | None
132    "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment."
133    source_id: str | None
134    "Source object identity (for example `ArchAstro/firstlanding`). `null` when the task has no source."
135    source_scope: str | None
136    "Container of the work this task is about (for example `github.com`). `null` when the task has no source. Set together with `source_type` and `source_id`."
137    source_type: str | None
138    "Kind of source object (for example `repository`). `null` when the task has no source."
139    stalled_since: datetime | None
140    "Lease expiry for a stalled task, or its last update when no lease expiry exists. Null when not stalled."
141    status: Required[str]
142    'Current status of the task. One of `"open"`, `"in_progress"`, `"in_review"`, `"paused"`, `"failed"`, `"superseding"`, `"done"`, or `"cancelled"`.'
143    subtasks_count: int | None
144    "Number of readable subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks."
145    tags: list[str] | None
146    "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged."
147    target_binary: str | None
148    "Binary that must run this work (for example `my-cli`). A worker should take the task only when its own `target_binary` build is at least `target_version`. `null` when the task has no target. Set together with `target_version`."
149    target_version: str | None
150    "Minimum semantic version of `target_binary` that can run this work (for example `0.48.9`), in canonical `MAJOR.MINOR.PATCH[-prerelease][+build]` form. `null` when the task has no target."
151    team: str | None
152    "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team."
153    thread: str | None
154    "ID of the thread this task is bound to (`thr_...`) - the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread."
155    updated_at: datetime | None
156    "When the task was last modified (ISO 8601)."
157    user: str | None
158    "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team."
159
160
161class TasksUpdatedPayload(TypedDict, total=False):
162    "Broadcast when the thread's task records change; carries a full snapshot"
163
164    tasks: list[TasksUpdatedPayloadTasksItem] | None
165
166
167# Phoenix channel for live task-record updates.
168# Clients join `api:tasks:thread:{thread_id}` to receive the thread's current
169# event-sourced tasks and subscribe to changes. The join reply carries a full
170# snapshot (`%{tasks: [...]}`), and every subsequent change lands as a
171# `tasks_updated` push carrying a fresh snapshot   the same replace-wholesale
172# contract expected by task-panel clients, so clients need no
173# delta bookkeeping.
174# Change signals originate from `ArchAstro.Tasks.Projectors.TaskProjector`,
175# which broadcasts on `"tasks:thread:{thread_id}"` after each committed
176# projection. Bursts (e.g. a mirror reconcile dispatching several commands)
177# are coalesced: the first signal arms a short timer and the reload happens
178# once, after the burst settles.
179class ApiTasksChannel:
180    def __init__(self, channel, join_response=None):
181        self._channel = channel
182        self.join_response = join_response
183
184    # Join a thread's live task list
185    @staticmethod
186    def topic_thread(thread_id: str) -> str:
187        return f"api:tasks:thread:{thread_id}"
188
189    # Join a thread's live task list
190    @classmethod
191    async def join_thread(cls, socket: "Socket", thread_id: str) -> "ApiTasksChannel":
192        topic = cls.topic_thread(thread_id)
193        channel = socket.channel(topic)
194        join_response = await channel.join()
195        return cls(channel, join_response)
196
197    # Leave the underlying channel.
198    async def leave(self):
199        await self._channel.leave()
200
201    # Broadcast when the thread's task records change; carries a full snapshot
202    def on_tasks_updated(
203        self, callback: Callable[[TasksUpdatedPayload], None]
204    ) -> Callable[[], None]:
205        return self._channel.on("tasks_updated", callback)
class TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture(typing.TypedDict):
14class TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture(TypedDict, total=False):
15    file: str | None
16    "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file."
17    height: int | None
18    "Height of the image in pixels. `null` if not known."
19    media: str | None
20    "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity."
21    mime_type: str | None
22    'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.'
23    refresh_url: str | None
24    "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing."
25    url: str | None
26    "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires."
27    width: int | None
28    "Width of the image in pixels. `null` if not known."
file: str | None

ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.

height: int | None

Height of the image in pixels. null if not known.

media: str | None

ID of the associated media record (med_...). null when the image is not linked to a media entity.

mime_type: str | None

MIME type of the image, e.g. "image/png" or "image/jpeg". null if not known.

refresh_url: str | None

Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.

url: str | None

Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.

width: int | None

Width of the image in pixels. null if not known.

class TasksUpdatedPayloadTasksItemCreatedByActor(typing.TypedDict):
31class TasksUpdatedPayloadTasksItemCreatedByActor(TypedDict, total=False):
32    alias: str | None
33    "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured."
34    id: str | None
35    'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.'
36    name: str | None
37    "Display name of the actor shown in the UI. `null` if no name is set."
38    profile_picture: TasksUpdatedPayloadTasksItemCreatedByActorProfilePicture | None
39    "Profile picture for the actor. `null` if the actor has no profile picture."
alias: str | None

Short handle or alias for the actor, used as an alternate display identifier. null if not configured.

id: str | None

Composite actor identifier. Format is "user-<usr_...>" for human users or "agent-<agi_...>" for agents.

name: str | None

Display name of the actor shown in the UI. null if no name is set.

Profile picture for the actor. null if the actor has no profile picture.

class TasksUpdatedPayloadTasksItemCurrentLease(typing.TypedDict):
42class TasksUpdatedPayloadTasksItemCurrentLease(TypedDict):
43    expires_at: datetime
44    "Server-calculated lease expiry in ISO 8601 format."
45    harness: str
46    "Bounded harness identifier for the coding session."
47    session_name: str
48    "Display name supplied by the coding session that holds the lease."
expires_at: datetime.datetime

Server-calculated lease expiry in ISO 8601 format.

harness: str

Bounded harness identifier for the coding session.

session_name: str

Display name supplied by the coding session that holds the lease.

class TasksUpdatedPayloadTasksItemOwnerActorProfilePicture(typing.TypedDict):
51class TasksUpdatedPayloadTasksItemOwnerActorProfilePicture(TypedDict, total=False):
52    file: str | None
53    "ID of the underlying storage file (`fil_...`). `null` when the image is not backed by a platform storage file."
54    height: int | None
55    "Height of the image in pixels. `null` if not known."
56    media: str | None
57    "ID of the associated media record (`med_...`). `null` when the image is not linked to a media entity."
58    mime_type: str | None
59    'MIME type of the image, e.g. `"image/png"` or `"image/jpeg"`. `null` if not known.'
60    refresh_url: str | None
61    "Endpoint URL you can call to obtain a fresh signed `url` when the current one has expired. `null` if the URL does not require refreshing."
62    url: str | None
63    "Signed or public URL for downloading the image. May be time-limited; use `refresh_url` to obtain a new URL when this one expires."
64    width: int | None
65    "Width of the image in pixels. `null` if not known."
file: str | None

ID of the underlying storage file (fil_...). null when the image is not backed by a platform storage file.

height: int | None

Height of the image in pixels. null if not known.

media: str | None

ID of the associated media record (med_...). null when the image is not linked to a media entity.

mime_type: str | None

MIME type of the image, e.g. "image/png" or "image/jpeg". null if not known.

refresh_url: str | None

Endpoint URL you can call to obtain a fresh signed url when the current one has expired. null if the URL does not require refreshing.

url: str | None

Signed or public URL for downloading the image. May be time-limited; use refresh_url to obtain a new URL when this one expires.

width: int | None

Width of the image in pixels. null if not known.

class TasksUpdatedPayloadTasksItemOwnerActor(typing.TypedDict):
68class TasksUpdatedPayloadTasksItemOwnerActor(TypedDict, total=False):
69    alias: str | None
70    "Short handle or alias for the actor, used as an alternate display identifier. `null` if not configured."
71    id: str | None
72    'Composite actor identifier. Format is `"user-<usr_...>"` for human users or `"agent-<agi_...>"` for agents.'
73    name: str | None
74    "Display name of the actor shown in the UI. `null` if no name is set."
75    profile_picture: TasksUpdatedPayloadTasksItemOwnerActorProfilePicture | None
76    "Profile picture for the actor. `null` if the actor has no profile picture."
alias: str | None

Short handle or alias for the actor, used as an alternate display identifier. null if not configured.

id: str | None

Composite actor identifier. Format is "user-<usr_...>" for human users or "agent-<agi_...>" for agents.

name: str | None

Display name of the actor shown in the UI. null if no name is set.

Profile picture for the actor. null if the actor has no profile picture.

class TasksUpdatedPayloadTasksItem(typing.TypedDict):
 79class TasksUpdatedPayloadTasksItem(TypedDict, total=False):
 80    agent: str | None
 81    "ID of the agent that owns this task (`agi_...`). `null` if the task is scoped to a team or user."
 82    aggregate_version: int | None
 83    "Event-stream version for optimistic update fencing. Pass this value as `expected_version` on an update to reject concurrent writes."
 84    blocked_by_count: int | None
 85    "Number of readable tasks marked as blocking this task, whether or not they are done (see `GET /tasks/{task}/blockers`). Computed on list/show reads; create/update responses may lag one read behind."
 86    closed_at: datetime | None
 87    "When the task was marked as done or otherwise closed (ISO 8601). `null` if the task is still open."
 88    comments_count: int | None
 89    "Total number of comments posted on this task."
 90    created_at: datetime | None
 91    "When the task was created (ISO 8601)."
 92    created_by_actor: TasksUpdatedPayloadTasksItemCreatedByActor | None
 93    "Resolved creator details including `id`, `name`, `alias`, and `profile_picture`. `null` if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted)."
 94    created_by_agent: str | None
 95    "ID of the agent that created this task (`agi_...`). `null` if the task was created by a human user, or if the creating agent was later deleted."
 96    created_by_user: str | None
 97    "ID of the user who created this task (`usr_...`). `null` if the task was created by an agent, or if creator provenance was cleared after the creator was deleted."
 98    current_lease: TasksUpdatedPayloadTasksItemCurrentLease | None
 99    "Viewer-safe live coding-session lease summary. `null` when the task is unleased or the projected lease has expired. Fencing identifiers are never included."
100    description: str | None
101    "Long-form description or notes for the task. `null` if no description has been provided."
102    due_date: datetime | None
103    "Date and time by which the task should be completed (ISO 8601). `null` if no due date is set."
104    epic: str | None
105    "Free-form grouping label. `null` when the task is not in an epic."
106    id: Required[str]
107    "Task ID (`tsk_...`)."
108    is_blocked: bool | None
109    "`true` while at least one blocking task is not yet done. Informational only - a blocked task can still change status - and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on reads, including mutation responses."
110    is_stalled: bool | None
111    "True exactly when status is in_progress and the task has no lease or its lease expiry is in the past. Derived at read time from status and lease expiry, including on unannotated reads."
112    links: dict[str, Any] | None
113    "Key-value map of named URLs or references associated with the task. Returns an empty object when no links have been set."
114    metadata: dict[str, Any] | None
115    "Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set."
116    name: Required[str]
117    "Human-readable title of the task."
118    org: str | None
119    "ID of the organization this task belongs to (`org_...`). `null` for tasks outside an org context."
120    owner_actor: TasksUpdatedPayloadTasksItemOwnerActor | None
121    "Resolved owner details including `id`, `name`, `alias`, and `profile_picture`. `null` if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted)."
122    owner_agent: str | None
123    "ID of the agent assigned as owner (`agi_...`). `null` if the owner is a human user, the task is unassigned, or the assigned agent was deleted."
124    owner_user: str | None
125    "ID of the user assigned as owner (`usr_...`). `null` if the owner is an agent, the task is unassigned, or the assigned agent was deleted."
126    parent: str | None
127    "ID of the parent task when this task is a subtask (`tsk_...`). `null` for top-level tasks or when the parent is not readable. Subtasks nest exactly one level."
128    priority: int | None
129    "Priority level of the task from `0` (highest) to `4` (lowest). Defaults to `2` (medium) when not explicitly set."
130    project_id: str | None
131    "Optional project ID (`prj_...`). Membership does not change task visibility."
132    sandbox: str | None
133    "ID of the developer sandbox this task is scoped to (`dsb_...`). `null` for tasks outside a sandbox environment."
134    source_id: str | None
135    "Source object identity (for example `ArchAstro/firstlanding`). `null` when the task has no source."
136    source_scope: str | None
137    "Container of the work this task is about (for example `github.com`). `null` when the task has no source. Set together with `source_type` and `source_id`."
138    source_type: str | None
139    "Kind of source object (for example `repository`). `null` when the task has no source."
140    stalled_since: datetime | None
141    "Lease expiry for a stalled task, or its last update when no lease expiry exists. Null when not stalled."
142    status: Required[str]
143    'Current status of the task. One of `"open"`, `"in_progress"`, `"in_review"`, `"paused"`, `"failed"`, `"superseding"`, `"done"`, or `"cancelled"`.'
144    subtasks_count: int | None
145    "Number of readable subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks."
146    tags: list[str] | None
147    "Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged."
148    target_binary: str | None
149    "Binary that must run this work (for example `my-cli`). A worker should take the task only when its own `target_binary` build is at least `target_version`. `null` when the task has no target. Set together with `target_version`."
150    target_version: str | None
151    "Minimum semantic version of `target_binary` that can run this work (for example `0.48.9`), in canonical `MAJOR.MINOR.PATCH[-prerelease][+build]` form. `null` when the task has no target."
152    team: str | None
153    "ID of the team that owns this task (`tem_...`). `null` if the task is not scoped to a team."
154    thread: str | None
155    "ID of the thread this task is bound to (`thr_...`) - the conversation it was filed from, or the thread passed at creation. `null` for tasks not tied to a thread."
156    updated_at: datetime | None
157    "When the task was last modified (ISO 8601)."
158    user: str | None
159    "ID of the user that owns this task (`usr_...`). `null` if the task is scoped to a team."
agent: str | None

ID of the agent that owns this task (agi_...). null if the task is scoped to a team or user.

aggregate_version: int | None

Event-stream version for optimistic update fencing. Pass this value as expected_version on an update to reject concurrent writes.

blocked_by_count: int | None

Number of readable tasks marked as blocking this task, whether or not they are done (see GET /tasks/{task}/blockers). Computed on list/show reads; create/update responses may lag one read behind.

closed_at: datetime.datetime | None

When the task was marked as done or otherwise closed (ISO 8601). null if the task is still open.

comments_count: int | None

Total number of comments posted on this task.

created_at: datetime.datetime | None

When the task was created (ISO 8601).

Resolved creator details including id, name, alias, and profile_picture. null if no creator is set or the creator cannot be resolved (e.g. creating agent was deleted).

created_by_agent: str | None

ID of the agent that created this task (agi_...). null if the task was created by a human user, or if the creating agent was later deleted.

created_by_user: str | None

ID of the user who created this task (usr_...). null if the task was created by an agent, or if creator provenance was cleared after the creator was deleted.

Viewer-safe live coding-session lease summary. null when the task is unleased or the projected lease has expired. Fencing identifiers are never included.

description: str | None

Long-form description or notes for the task. null if no description has been provided.

due_date: datetime.datetime | None

Date and time by which the task should be completed (ISO 8601). null if no due date is set.

epic: str | None

Free-form grouping label. null when the task is not in an epic.

id: Required[str]

Task ID (tsk_...).

is_blocked: bool | None

true while at least one blocking task is not yet done. Informational only - a blocked task can still change status - and derived at read time, so the task un-blocks automatically when its last open blocker completes. Computed on reads, including mutation responses.

is_stalled: bool | None

True exactly when status is in_progress and the task has no lease or its lease expiry is in the past. Derived at read time from status and lease expiry, including on unannotated reads.

metadata: dict[str, typing.Any] | None

Arbitrary key-value map of application-specific data stored alongside the task. Returns an empty object when no metadata has been set.

name: Required[str]

Human-readable title of the task.

org: str | None

ID of the organization this task belongs to (org_...). null for tasks outside an org context.

Resolved owner details including id, name, alias, and profile_picture. null if the task is unassigned or the owner cannot be resolved (e.g. assigned agent was deleted).

owner_agent: str | None

ID of the agent assigned as owner (agi_...). null if the owner is a human user, the task is unassigned, or the assigned agent was deleted.

owner_user: str | None

ID of the user assigned as owner (usr_...). null if the owner is an agent, the task is unassigned, or the assigned agent was deleted.

parent: str | None

ID of the parent task when this task is a subtask (tsk_...). null for top-level tasks or when the parent is not readable. Subtasks nest exactly one level.

priority: int | None

Priority level of the task from 0 (highest) to 4 (lowest). Defaults to 2 (medium) when not explicitly set.

project_id: str | None

Optional project ID (prj_...). Membership does not change task visibility.

sandbox: str | None

ID of the developer sandbox this task is scoped to (dsb_...). null for tasks outside a sandbox environment.

source_id: str | None

Source object identity (for example ArchAstro/firstlanding). null when the task has no source.

source_scope: str | None

Container of the work this task is about (for example github.com). null when the task has no source. Set together with source_type and source_id.

source_type: str | None

Kind of source object (for example repository). null when the task has no source.

stalled_since: datetime.datetime | None

Lease expiry for a stalled task, or its last update when no lease expiry exists. Null when not stalled.

status: Required[str]

Current status of the task. One of "open", "in_progress", "in_review", "paused", "failed", "superseding", "done", or "cancelled".

subtasks_count: int | None

Number of readable subtasks under this task. Computed on list/show reads; create/update responses may report 0 until the next read. Always 0 for subtasks.

tags: list[str] | None

Labels for grouping and filtering, stored lowercase and de-duplicated. Empty array when untagged.

target_binary: str | None

Binary that must run this work (for example my-cli). A worker should take the task only when its own target_binary build is at least target_version. null when the task has no target. Set together with target_version.

target_version: str | None

Minimum semantic version of target_binary that can run this work (for example 0.48.9), in canonical MAJOR.MINOR.PATCH[-prerelease][+build] form. null when the task has no target.

team: str | None

ID of the team that owns this task (tem_...). null if the task is not scoped to a team.

thread: str | None

ID of the thread this task is bound to (thr_...) - the conversation it was filed from, or the thread passed at creation. null for tasks not tied to a thread.

updated_at: datetime.datetime | None

When the task was last modified (ISO 8601).

user: str | None

ID of the user that owns this task (usr_...). null if the task is scoped to a team.

class TasksUpdatedPayload(typing.TypedDict):
162class TasksUpdatedPayload(TypedDict, total=False):
163    "Broadcast when the thread's task records change; carries a full snapshot"
164
165    tasks: list[TasksUpdatedPayloadTasksItem] | None

Broadcast when the thread's task records change; carries a full snapshot

tasks: list[TasksUpdatedPayloadTasksItem] | None
class ApiTasksChannel:
180class ApiTasksChannel:
181    def __init__(self, channel, join_response=None):
182        self._channel = channel
183        self.join_response = join_response
184
185    # Join a thread's live task list
186    @staticmethod
187    def topic_thread(thread_id: str) -> str:
188        return f"api:tasks:thread:{thread_id}"
189
190    # Join a thread's live task list
191    @classmethod
192    async def join_thread(cls, socket: "Socket", thread_id: str) -> "ApiTasksChannel":
193        topic = cls.topic_thread(thread_id)
194        channel = socket.channel(topic)
195        join_response = await channel.join()
196        return cls(channel, join_response)
197
198    # Leave the underlying channel.
199    async def leave(self):
200        await self._channel.leave()
201
202    # Broadcast when the thread's task records change; carries a full snapshot
203    def on_tasks_updated(
204        self, callback: Callable[[TasksUpdatedPayload], None]
205    ) -> Callable[[], None]:
206        return self._channel.on("tasks_updated", callback)
ApiTasksChannel(channel, join_response=None)
181    def __init__(self, channel, join_response=None):
182        self._channel = channel
183        self.join_response = join_response
join_response
@staticmethod
def topic_thread(thread_id: str) -> str:
186    @staticmethod
187    def topic_thread(thread_id: str) -> str:
188        return f"api:tasks:thread:{thread_id}"
@classmethod
async def join_thread( cls, socket: archastro.phx_channel.Socket, thread_id: str) -> ApiTasksChannel:
191    @classmethod
192    async def join_thread(cls, socket: "Socket", thread_id: str) -> "ApiTasksChannel":
193        topic = cls.topic_thread(thread_id)
194        channel = socket.channel(topic)
195        join_response = await channel.join()
196        return cls(channel, join_response)
async def leave(self):
199    async def leave(self):
200        await self._channel.leave()
def on_tasks_updated( self, callback: Callable[[TasksUpdatedPayload], None]) -> Callable[[], None]:
203    def on_tasks_updated(
204        self, callback: Callable[[TasksUpdatedPayload], None]
205    ) -> Callable[[], None]:
206        return self._channel.on("tasks_updated", callback)