@@ -79,6 +79,8 @@ def __init__(self, api_base: str, issue: int, token: str,
7979 self ._last_push = 0.0
8080 self ._timer : Optional [threading .Timer ] = None
8181 self ._lock = threading .Lock ()
82+ # Populated by _load_yaml_steps_as_todos: role_name.lower() -> step index
83+ self ._step_agent_map : Dict [str , int ] = {}
8284
8385 # ------------------------------------------------------------------
8486 # Public API
@@ -118,12 +120,26 @@ def on_agent_start(self, agent_name: str) -> None:
118120 with self ._lock :
119121 self ._current_agent = agent_name
120122 self ._logs .append (f"🤖 Agent starting: **{ agent_name } **" )
123+ # Mark matching step as in_progress
124+ idx = self ._step_agent_map .get (agent_name .lower ())
125+ if idx is not None and idx < len (self ._todos ):
126+ for t in self ._todos :
127+ if t ["status" ] == "in_progress" :
128+ t ["status" ] = "completed"
129+ self ._todos [idx ]["status" ] = "in_progress"
121130 self ._schedule_push ()
122131
123132 def on_agent_end (self , agent_name : str ) -> None :
124133 with self ._lock :
125134 self ._logs .append (f"✅ Agent completed: **{ agent_name } **" )
126135 self ._current_agent = None
136+ # Mark matching step as completed
137+ idx = self ._step_agent_map .get (agent_name .lower ())
138+ if idx is not None and idx < len (self ._todos ):
139+ self ._todos [idx ]["status" ] = "completed"
140+ # Mark next step as in_progress if it exists
141+ if idx + 1 < len (self ._todos ) and self ._todos [idx + 1 ]["status" ] == "pending" :
142+ self ._todos [idx + 1 ]["status" ] = "in_progress"
127143 self ._schedule_push ()
128144
129145 def on_tool_start (self , agent_name : str , tool_name : str , tool_args : dict ) -> None :
@@ -310,6 +326,61 @@ def close(self) -> None:
310326 return GithubContextSink ()
311327
312328
329+ # ---------------------------------------------------------------------------
330+ # YAML step → todo pre-loader
331+ # ---------------------------------------------------------------------------
332+
333+ def _load_yaml_steps_as_todos (agent_file : str , sticky : StickyComment ) -> None :
334+ """Parse the agent YAML and populate todos from step names/agents."""
335+ try :
336+ import yaml # type: ignore
337+ except ImportError :
338+ return
339+ try :
340+ with open (agent_file ) as f :
341+ cfg = yaml .safe_load (f )
342+ except Exception :
343+ return
344+ if not isinstance (cfg , dict ):
345+ return
346+
347+ steps = cfg .get ("steps" , [])
348+ roles = cfg .get ("roles" , {})
349+ if not steps :
350+ return
351+
352+ todos = []
353+ for step in steps :
354+ if not isinstance (step , dict ):
355+ continue
356+ # Prefer explicit step name; fall back to role display name or agent key
357+ step_name = step .get ("name" , "" )
358+ agent_key = step .get ("agent" , "" )
359+ if not step_name and agent_key :
360+ role_cfg = roles .get (agent_key , {})
361+ step_name = role_cfg .get ("role" , agent_key ).title ()
362+ if step_name :
363+ # Humanize snake_case → Title Case
364+ human_name = step_name .replace ("_" , " " ).title ()
365+ todos .append ({"content" : human_name , "status" : "pending" })
366+
367+ if todos :
368+ # Mark first as in_progress
369+ todos [0 ]["status" ] = "in_progress"
370+ with sticky ._lock :
371+ sticky ._todos = todos
372+
373+ # Build a reverse map: agent role name → step index for the sink to use
374+ sticky ._step_agent_map = {}
375+ for i , step in enumerate (steps ):
376+ if not isinstance (step , dict ):
377+ continue
378+ agent_key = step .get ("agent" , "" )
379+ role_cfg = roles .get (agent_key , {})
380+ role_name = role_cfg .get ("role" , agent_key )
381+ sticky ._step_agent_map [role_name .lower ()] = i
382+
383+
313384# ---------------------------------------------------------------------------
314385# CLI command
315386# ---------------------------------------------------------------------------
@@ -375,6 +446,10 @@ def github_triage(
375446 task_type = task_type , title = ctx_title , run_url = run_url ,
376447 )
377448 sticky ._logs .append (f"Context fetched for { task_type } #{ issue } " )
449+
450+ # Pre-populate todo list from YAML steps
451+ _load_yaml_steps_as_todos (agent_file , sticky )
452+
378453 sticky .post_initial ()
379454
380455 # ------------------------------------------------------------------
0 commit comments