The board edits the agent task database through the Python MCP server, which now lives in this module (Taskboard/server). Code is versioned here; the data (tasks.db and per-task session workspaces) stays in AGENTS_DATA_DIR, by default ~/agents/manager, decided only in server/paths.py. UI: - Tasks are graph nodes; parent/child and dependency links map to set_parent and dependencies. Dropping a link on empty space creates a connected task. - Inspector edits title, description, status, priority, model, effort, permission mode and colour. - Edits stay local until Save (Ctrl+S, File > Save); the status bar shows the unsaved count. Unsaved work is the difference between the board and the last server board (BoardSnapshot), saved atomically with save_board. - Server changes merge in on a one-second poll without touching unsaved edits; the same field changed on both sides becomes a keep-mine/use-theirs conflict. - Sessions: start, stop, restart with new settings (keeping or dropping the conversation), open in a terminal, send messages; a node badge shows the live session state. Server: - Headless Claude Code sessions, one tmux session per task, with state from hooks and the exit reason recorded; manual or auto permission modes. - save_board, edit_task conflict checks, field history, get_board and revision polling, session tools, task workspaces with report conventions.
29 lines
991 B
Python
29 lines
991 B
Python
"""Runs in the task's tmux session after the agent process exits: records why it ended."""
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from sessions import exit_marker_path, last_exit_reason, set_state # noqa: E402
|
|
|
|
|
|
def main():
|
|
task_id, status = int(sys.argv[1]), sys.argv[2]
|
|
reason = last_exit_reason(task_id)
|
|
detail = f"exited with code {status}" + (f": {reason}" if reason else "")
|
|
set_state(task_id, "ended", "finished" if status == "0" and not reason else detail)
|
|
with open(exit_marker_path(task_id), "w") as marker:
|
|
marker.write(status)
|
|
notify_waiter(os.environ.get("AGENTS_EXIT_FIFO"), task_id, status)
|
|
|
|
|
|
def notify_waiter(fifo, task_id, status):
|
|
"""Tests block on a FIFO instead of polling; nothing listens in normal use."""
|
|
if not fifo or not os.path.exists(fifo):
|
|
return
|
|
with open(fifo, "w") as pipe:
|
|
pipe.write(f"{task_id} {status}\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|