tasks
tasks
¶
Task metadata, lifecycle, and query operations.
Provides module-level functions for CRUD over YAML-backed task metadata.
Container runner functions (task_run_cli,
task_run_headless, task_restart) live in the companion
task_runners module. Display types and status computation live in
task_display. Log viewing lives in task_logs.
TASK_NAME_MAX_LEN = 60
module-attribute
¶
Maximum length of a sanitized task name.
TaskMeta(container_state=None, exit_code=None, deleting=False, initialized=False, *, task_id, mode, workspace, web_port, backend=None, preset=None, name='', provider=None, unrestricted=None, work_status=None, work_message=None, shield_state=None)
dataclass
¶
ArchivedTask(archive_dir, archived_at, task_id, name, mode, exit_code)
dataclass
¶
Metadata snapshot of an archived (deleted) task.
container_name(project_id, mode, task_id)
¶
get_task_container_state(project_id, task_id, mode)
¶
Get actual container state for a task (TUI helper).
Source code in src/terok/lib/orchestration/tasks.py
sanitize_task_name(raw)
¶
Sanitize a raw task name into a slug-style identifier.
Strips whitespace, lowercases, replaces spaces with hyphens,
removes characters outside [a-z0-9_-], collapses consecutive
hyphens, strips trailing hyphens, and truncates to
TASK_NAME_MAX_LEN. Returns None if the result is empty.
Leading hyphens are preserved so callers can detect and reject them
(a name starting with - looks like a CLI flag).
Source code in src/terok/lib/orchestration/tasks.py
validate_task_name(sanitized)
¶
Return an error message if sanitized is not a valid task name, else None.
A name is invalid if it starts with a hyphen (looks like a CLI flag).
Callers should first check for None from :func:sanitize_task_name
(which indicates the name was empty after sanitization).
Source code in src/terok/lib/orchestration/tasks.py
generate_task_name(project_id=None)
¶
Generate a random human-readable task name (e.g. talented-toucan).
When project_id is given, name categories are resolved from config:
project tasks.name_categories → global tasks.name_categories
→ deterministic 3-category selection based on project ID hash.
Source code in src/terok/lib/orchestration/tasks.py
get_task_meta(project_id, task_id)
¶
Return metadata for a single task with live container state.
Hydrates container_state from the running container so that
TaskMeta.status reflects current reality rather than stale YAML.
Raises SystemExit if the task metadata file is not found.
Source code in src/terok/lib/orchestration/tasks.py
get_workspace_git_diff(project_id, task_id, against='HEAD')
¶
Get git diff from a task's workspace via container exec.
Runs git diff inside the task container rather than on the host,
so that even poisoned git hooks only execute within the container sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id
|
str
|
The project ID |
required |
task_id
|
str
|
The task ID |
required |
against
|
str
|
What to diff against ( |
'HEAD'
|
Returns:
| Type | Description |
|---|---|
str | None
|
The git diff output as a string, or |
Source code in src/terok/lib/orchestration/tasks.py
tasks_meta_dir(project_id)
¶
Return the directory containing task metadata YAML files for project_id.
tasks_archive_dir(project_id)
¶
Return the directory containing archived task data for project_id.
update_task_exit_code(project_id, task_id, exit_code)
¶
Update task metadata with exit code and final status.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id
|
str
|
The project ID |
required |
task_id
|
str
|
The task ID |
required |
exit_code
|
int | None
|
The exit code from the task, or None if unknown/failed |
required |
Source code in src/terok/lib/orchestration/tasks.py
task_new(project_id, *, name=None)
¶
Create a new task with a fresh workspace for a project.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id
|
str
|
The project to create the task under. |
required |
name
|
str | None
|
Optional human-readable name. Allowed characters are
lowercase letters, digits, hyphens, and underscores.
If |
None
|
Workspace Initialization Protocol:¶
Each task gets its own workspace directory that persists across container runs. When a container starts, the init script (init-ssh-and-repo.sh) needs to know whether this is:
- A NEW task that should be reset to the latest remote HEAD
- A RESTARTED task where local changes should be preserved
We use a marker file (.new-task-marker) to signal intent:
- task_new() creates the marker in the workspace directory
- init-ssh-and-repo.sh checks for the marker:
- If marker exists: reset to origin/HEAD, then delete marker
- If no marker: fetch only, preserve local state
- Subsequent container runs on the same task won't see the marker, so local work is preserved
This handles edge cases like: - Stale workspace from incompletely deleted previous task with same ID - Ensuring new tasks always start with latest code
Source code in src/terok/lib/orchestration/tasks.py
task_rename(project_id, task_id, new_name)
¶
Rename a task by updating its metadata YAML.
Sanitizes new_name and writes the result to the task's metadata file.
Raises SystemExit if the task is unknown or the sanitized name is invalid.
Source code in src/terok/lib/orchestration/tasks.py
get_tasks(project_id, reverse=False)
¶
Return all task metadata for project_id, sorted by task ID.
get_all_task_states(project_id, tasks)
¶
Map each task to its live container state via a single batch query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
project_id
|
str
|
The project whose containers to query. |
required |
tasks
|
list[TaskMeta]
|
List of |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str | None]
|
|
Source code in src/terok/lib/orchestration/tasks.py
task_list(project_id, *, status=None, mode=None, agent=None)
¶
List tasks for a project, optionally filtered by status, mode, or agent preset.
Status is computed live from podman container state + task metadata.
Source code in src/terok/lib/orchestration/tasks.py
load_task_meta(project_id, task_id, expected_mode=None)
¶
Load task metadata and optionally validate mode.
Returns (meta, meta_path). Raises SystemExit if task is unknown or mode conflicts with expected_mode.
Source code in src/terok/lib/orchestration/tasks.py
mark_task_deleting(project_id, task_id)
¶
Persist deleting: true to the task's YAML metadata file.
Source code in src/terok/lib/orchestration/tasks.py
capture_task_logs(project, task_id, mode)
¶
Capture container logs to the task's logs/ directory on the host.
Writes stdout/stderr from podman logs to
<tasks_root>/<task_id>/logs/container.log. Returns the log file
path on success, or None if the container doesn't exist or podman
fails.
project may be a :class:ProjectConfig or a project-ID string
(the string form loads the config internally for backward compat).
Source code in src/terok/lib/orchestration/tasks.py
task_delete(project_id, task_id)
¶
Delete a task's workspace, metadata, and any associated containers.
Before removing the task, captures container logs and archives the task
metadata and logs to <state_root>/projects/<project_id>/archive/.
The archive directory is named by archival timestamp + task ID + name
for unique identification (task numbers and names can be reused).
This mirrors the behavior used by the TUI when deleting a task, but is
exposed here so both CLI and TUI share the same logic. Containers are
stopped best-effort via podman using the naming scheme
"
Source code in src/terok/lib/orchestration/tasks.py
get_login_command(project_id, task_id)
¶
Return the podman exec command to log into a task container.
task_login(project_id, task_id)
¶
task_stop(project_id, task_id, *, timeout=None)
¶
Gracefully stop a running task container.
Uses podman stop --time <N> to give the container timeout seconds
before SIGKILL. When timeout is None the project's
run.shutdown_timeout setting is used (default 10 s).
Source code in src/terok/lib/orchestration/tasks.py
task_status(project_id, task_id)
¶
Show live task status with container state diagnostics.
Source code in src/terok/lib/orchestration/tasks.py
list_archived_tasks(project_id)
¶
Return archived tasks for project_id, sorted newest-first.
Source code in src/terok/lib/orchestration/tasks.py
task_archive_list(project_id)
¶
Print archived tasks for project_id.
Source code in src/terok/lib/orchestration/tasks.py
task_archive_logs(project_id, archive_id)
¶
Return the log file path for an archived task identified by archive_id.
archive_id is matched against archive directory names (prefix match).
Returns the log file path if found, or None.