tix

class shai_tix.tix.Tix(dir_root: pathlib.Path)[source]
session()[source]

Start a session with synchronized index database.

Rebuilds the SQLite index from filesystem on entry, ensuring all query_* methods return up-to-date results.

Usage:

tix = Tix(dir_root=path)
with tix.session():
    stories = tix.query_stories()
    tasks = tix.query_tasks()
Returns:

Context manager yielding self

iter_stories()[source]

Iterate over all story folders and yield Story objects.

Scans the stories directory and yields Story objects for each valid story folder found.

Returns:

Generator yielding Story objects

iter_tasks()[source]

Iterate over all task folders and yield Task objects.

Directly scans all task folders using glob pattern stories/*/tasks/* for better efficiency, avoiding per-story API calls.

Returns:

Generator yielding Task objects

iter_stories_or_tasks()[source]

Iterate over all stories and tasks using a single rglob scan.

Uses one rglob("*") call to scan all paths, then filters by folder name prefix (story- or task-). No is_dir() check needed since Ticket.from_folder() validates the naming pattern.

Paths are sorted to ensure depth-first order: each story appears before its tasks (shorter paths come first when sorted).

Returns:

Generator yielding Story or Task objects

ensure_dir_root()[source]

Ensure the root directory exists.

Creates the .tix directory if it doesn’t exist. This is called automatically before any database operations.

rebuild_index_db()[source]

Rebuild the SQLite index database from filesystem.

Scans all story and task folders, creates ORM objects, and writes them to the SQLite database. Existing data is cleared first.

ensure_index_db()[source]

Ensure the index database exists, rebuilding if necessary.

get_next_id() int[source]

Get the next available ID from the index database.

Stories and tasks share the same global ID space. This method queries the database for max ID and returns max_id + 1. If no entities exist, returns 1.

Returns:

Next available global ID

query_stories(limit: int = 20) list[Story][source]

Query all stories from the index database.

Use within context manager to ensure database is synchronized.

Parameters:

limit – Maximum number of stories to return

Returns:

List of all Story objects from database, sorted by ID descending

query_tasks(limit: int = 20) list[Task][source]

Query all tasks from the index database.

Use within context manager to ensure database is synchronized.

Parameters:

limit – Maximum number of tasks to return

Returns:

List of all Task objects from database, sorted by ID descending

query_story(id: int) Story | None[source]

Query a single story by ID from the index database.

Parameters:

id – Story ID to query

Returns:

Story object if found, None otherwise

query_task(id: int) Task | None[source]

Query a single task by ID from the index database.

Parameters:

id – Task ID to query

Returns:

Task object if found, None otherwise

search_stories(title: str | None = None, date_lower: str | None = None, date_upper: str | None = None, id_lower: int | None = None, id_upper: int | None = None, status: list[StatusEnum] | None = None, limit: int = 20) list[Story][source]

Search stories by title, date range, ID range, and/or status.

At least one parameter must be provided. Results are sorted by ID descending (newest first).

Title matching: tokenizes the search string (splits on spaces and special characters, lowercases), matches if any token appears in the story title.

Status matching: when status list is provided, only stories with status in the list are returned. This requires reading metadata.json for each candidate story.

Parameters:
  • title – Search string to match against story titles

  • date_lower – Minimum date (inclusive), format YYYY-MM-DD

  • date_upper – Maximum date (inclusive), format YYYY-MM-DD

  • id_lower – Minimum ID (inclusive)

  • id_upper – Maximum ID (inclusive)

  • status – List of status values to match (e.g., [StatusEnum.TODO, StatusEnum.IN_PROGRESS])

  • limit – Maximum number of stories to return

Returns:

List of matching Story objects, sorted by ID descending

Raises:

ValueError – If all parameters are None

search_tasks(title: str | None = None, date_lower: str | None = None, date_upper: str | None = None, id_lower: int | None = None, id_upper: int | None = None, status: list[StatusEnum] | None = None, limit: int = 20) list[Task][source]

Search tasks by title, date range, ID range, and/or status.

At least one parameter must be provided. Results are sorted by ID descending (newest first).

Title matching: tokenizes the search string (splits on spaces and special characters, lowercases), matches if any token appears in the task title.

Status matching: when status list is provided, only tasks with status in the list are returned. This requires reading metadata.json for each candidate task.

Parameters:
  • title – Search string to match against task titles

  • date_lower – Minimum date (inclusive), format YYYY-MM-DD

  • date_upper – Maximum date (inclusive), format YYYY-MM-DD

  • id_lower – Minimum ID (inclusive)

  • id_upper – Maximum ID (inclusive)

  • status – List of status values to match (e.g., [StatusEnum.TODO, StatusEnum.IN_PROGRESS])

  • limit – Maximum number of tasks to return

Returns:

List of matching Task objects, sorted by ID descending

Raises:

ValueError – If all parameters are None

create_story(title: str, description: str | None = None) Story[source]

Create a new story with auto-generated ID.

Automatically assigns the next available ID and updates the index database.

Parameters:
  • title – Story title (only letters, digits, and spaces allowed)

  • description – Optional story description

Returns:

Created Story object

Raises:

TitleValidationError – If title contains invalid characters

get_story(id: int) Story | None[source]

Get a story by ID from the index database.

Parameters:

id – Story ID to retrieve

Returns:

Story object if found, None otherwise

update_story(id: int, title: str | None = None, status: StatusEnum | None = None, description: str | None = None, report: str | None = None) Story | None[source]

Update a story’s metadata and content files.

Supports updating title, status, description, and report. When title changes, the story folder is renamed accordingly.

Parameters:
  • id – Story ID to update

  • title – New title (optional, triggers folder rename)

  • status – New status value (optional)

  • description – New description content (optional)

  • report – New report content (optional)

Returns:

Updated Story object, or None if story not found

delete_story(id: int) bool[source]

Delete a story by ID from filesystem and index database.

Removes the story directory and all its tasks from filesystem, then removes the story from the index database.

Parameters:

id – Story ID to delete

Returns:

True if deleted, False if story not found

create_task(story_id: int, title: str, description: str | None = None) Task[source]

Create a new task under a story with auto-generated ID.

Parameters:
  • story_id – Parent story ID

  • title – Task title (only letters, digits, and spaces allowed)

  • description – Optional task description

Returns:

Created Task object

Raises:
get_task(id: int) Task | None[source]

Get a task by ID from the index database.

Parameters:

id – Task ID to retrieve

Returns:

Task object if found, None otherwise

update_task(id: int, title: str | None = None, status: StatusEnum | None = None, description: str | None = None, report: str | None = None) Task | None[source]

Update a task’s metadata and content files.

Supports updating title, status, description, and report. When title changes, the task folder is renamed accordingly.

Parameters:
  • id – Task ID to update

  • title – New title (optional, triggers folder rename)

  • status – New status value (optional)

  • description – New description content (optional)

  • report – New report content (optional)

Returns:

Updated Task object, or None if task not found

delete_task(id: int) bool[source]

Delete a task by ID from filesystem and index database.

Parameters:

id – Task ID to delete

Returns:

True if deleted, False if task not found

query_tasks_by_story(story_id: int) list[Task][source]

Query all tasks belonging to a specific story.

Parameters:

story_id – Parent story ID

Returns:

List of Task objects belonging to the story, sorted by ID descending