
    PL
j5                       d Z ddlmZ ddlZddlZddlZddlmZmZ ddl	m
Z
mZ  ej        e          ZdZdZdd
ZddZddZddZddZddZd ZddZddZdddd"Zdd$Zdd&Zdd'Zdd(Zdd)Zdd*Z dd+Z!dd,Z"dd-Z#dd.Z$dd/Z%d0Z&d1d2d3dd4e&d5ig d6d7Z'd8d9d3d4d:d5d4g d;d<d=d4d>d5d?d@d5dAdBd5dCg d6d7Z(dDdEd3d4e&d5d4dFd5d3dGd5d4dHd5dIdJd4idKdLdMg d6d7Z)dNdOd3d4e&d5d4dPd5dQdRgd6d7Z*dSdTd3d4e&d5d4dUd5dVg d6d7Z+dWdXd3d4dYd5d4dZd5d[dd\gd6d7Z,d]d^d3d4d_d5d4d`d5d4dad5dIdJd4idbdLd4dcd5dAddd5d4g dedfd=d4dgd5d?dhd5d4did5dAdjd5dIdJd4idkdLdldmdngd6d7Z-dodpd3dd4dqd5idgd6d7Z.drdsd3d4dtd5d4dud5dvdwdxgd6d7Z/ e
j0        d1dye'eedz{            e
j0        d8dye(eedz{            e
j0        dDdye)eed|{            e
j0        dNdye*e ed}{            e
j0        dSdye+e!ed~{            e
j0        dWdye,e"ed{            e
j0        d]dye-e#ed{            e
j0        dodye.e$ed{            e
j0        drdye/e%ed{           dS )u  Kanban tools — structured tool-call surface for worker + orchestrator agents.

These tools are only registered into the model's schema when the agent is
running under the dispatcher (env var ``HERMES_KANBAN_TASK`` set). A
normal ``hermes chat`` session sees **zero** kanban tools in its schema.

Why tools instead of just shelling out to ``hermes kanban``?

1. **Backend portability.** A worker whose terminal tool points at Docker
   / Modal / Singularity / SSH would run ``hermes kanban complete …``
   inside the container, where ``hermes`` isn't installed and the DB
   isn't mounted. Tools run in the agent's Python process, so they
   always reach ``~/.hermes/kanban.db`` regardless of terminal backend.

2. **No shell-quoting footguns.** Passing ``--metadata '{"x": [...]}'``
   through shlex+argparse is fragile. Structured tool args skip it.

3. **Better errors.** Tool-call failures return structured JSON the
   model can reason about, not stderr strings it has to parse.

Humans continue to use the CLI (``hermes kanban …``), the dashboard
(``hermes dashboard``), and the slash command (``/kanban …``) — all
three bypass the agent entirely. The tools are ONLY for the worker
agent's handoff back to the kernel.
    )annotationsN)AnyOptional)registry
tool_error2      returnboolc                 z    	 ddl m}   |             }|                    dg           }d|v S # t          $ r Y dS w xY w)Nr   )load_configtoolsetskanbanF)hermes_cli.configr   get	Exception)r   cfgr   s      6/home/kuhnn/.hermes/hermes-agent/tools/kanban_tools.py_profile_has_kanban_toolsetr   .   sd    111111kmm77:r**8##   uus   ), 
::c                 `    t           j                            d          rdS t                      S )a  Task-lifecycle tools are available when:

    1. ``HERMES_KANBAN_TASK`` is set (dispatcher-spawned worker), OR
    2. The current profile has ``kanban`` in its toolsets config
       (orchestrator profiles like techlead that route work via Kanban).

    Humans running ``hermes chat`` without the kanban toolset see zero
    kanban tools. Workers spawned by the kanban dispatcher (gateway-
    embedded by default) and orchestrator profiles with the kanban
    toolset enabled see the Kanban lifecycle tool surface.
    HERMES_KANBAN_TASKTosenvironr   r        r   _check_kanban_moder   ;   s,     
z~~*++ t&(((r   c                 `    t           j                            d          rdS t                      S )a  Board-routing tools (kanban_list, kanban_unblock) are intentionally
    hidden from task workers.

    Dispatcher-spawned workers should close their own task via the
    lifecycle tools (complete/block/heartbeat), not enumerate or unblock
    board state. Profiles that explicitly opt into the kanban toolset
    and are NOT scoped to a single task are the orchestrator surface.
    r   Fr   r   r   r   _check_kanban_orchestrator_moder   L   s,     
z~~*++ u&(((r   argOptional[str]c                P    | r| S t           j                            d          }|pdS )zGResolve ``task_id`` arg or fall back to the env var the dispatcher set.r   N)r   r   r   )r    env_tids     r   _default_task_idr$   ^   s-    
 
jnn122G?dr   task_idstrOptional[int]c                    t           j                            d          | k    rdS t           j                            d          }|sdS 	 t          |          S # t          $ r Y dS w xY w)zDReturn this worker's dispatcher run id when it is scoped to task_id.r   NHERMES_KANBAN_RUN_ID)r   r   r   int
ValueError)r%   raws     r   _worker_run_idr-   f   st    	z~~*++w66t
*../
0
0C t3xx   tts   
A 
A'&A'tidc                    t           j                            d          }|sdS | |k    rt          d| d|  d          S dS )u_  Reject worker-driven destructive calls on foreign task IDs.

    A process spawned by the dispatcher has ``HERMES_KANBAN_TASK`` set
    to its own task id. Tools like ``kanban_complete`` / ``kanban_block``
    / ``kanban_heartbeat`` mutate run-lifecycle state, so a buggy or
    prompt-injected worker that passed an explicit ``task_id`` for some
    other task could corrupt sibling or cross-tenant runs (see #19534).

    Orchestrator profiles (kanban toolset enabled but **no**
    ``HERMES_KANBAN_TASK`` in env) aren't subject to this check — their
    job is routing, and they sometimes legitimately close out child
    tasks or reopen blocked ones. Workers are narrowly scoped to their
    one task.

    Returns ``None`` when the call is allowed, or a tool-error string
    when it must be rejected. Callers should ``return`` the error
    verbatim.
    r   Nzworker is scoped to task z; refusing to mutate zf. Use kanban_comment to hand off information to other tasks, or kanban_create to spawn follow-up work.r   r   r   r   )r.   r#   s     r   _enforce_worker_task_ownershipr1   s   sp    & jnn122G t
g~~@ @ @@ @ @
 
 	

 4r   c                 :    ddl m}  | |                                 fS )zImport + connect lazily so the module imports cleanly in non-kanban
    contexts (e.g. test rigs that import every tool module).r   )	kanban_db)
hermes_clir3   connect)kbs    r   _connectr7      s)     +*****rzz||r   fieldsr   c                 2    t          j        ddi|           S )NokT)jsondumps)r8   s    r   _okr=      s    :tT,V,---r   valuec                    | dS t          |                                           }|r|                                dv rdS |S )zANormalize CLI-compatible assignee sentinels for the tool surface.N>   -nonenull)r&   striplower)r>   texts     r   _normalize_profilerF      sH    }tu::D 4::<<#888tKr   F)defaultargsdictnamerG   c                   |                      |          }||d fS t          |t                    r|d fS t          |                                                                          }|dv rdS |dv rdS || dfS )N>   1yestrue)TN>   0nofalse)FNz$ must be a boolean or 'true'/'false')r   
isinstancer   r&   rC   rD   )rH   rJ   rG   r>   rE   s        r   _parse_bool_argrS      s    HHTNNE}}% d{u::##%%D###z###{tAAAAAr   	tool_namec                h    t           j                            d          rt          |  d          S dS )a  Belt-and-suspenders runtime guard for orchestrator-only handlers.

    The check_fn (`_check_kanban_orchestrator_mode`) keeps these tools
    out of the worker schema entirely, but in case a stale registration
    or test harness routes a worker to one of them anyway, return a
    structured tool_error so the model gets a clear refusal instead of
    silently mutating board state from a worker context.
    r   z is orchestrator-only; dispatcher-spawned workers must use kanban_complete, kanban_block, kanban_heartbeat, or kanban_comment for their assigned task.Nr0   )rT   s    r   _require_orchestrator_toolrV      sF     
z~~*++ 
 6 6 6
 
 	

 4r   dict[str, Any]c                   |                      ||j                  }|                     ||j                  }i d|j        d|j        d|j        d|j        d|j        d|j        d|j        d|j	        d	|j
        d
|j        d|j        d|j        d|j        d|d|dt          |          dt          |          S )z+Compact task shape for board-listing tools.idtitleassigneestatusprioritytenantworkspace_kindworkspace_path
created_by
created_at
started_atcompleted_atcurrent_run_idparentschildrenparent_countchild_count)
parent_idsrY   	child_idsrZ   r[   r\   r]   r^   r_   r`   ra   rb   rc   rd   re   len)r6   conntaskrf   rg   s        r   _task_summary_dictro      s(   mmD$'**G||D$'**Hdg 	DM 	$+	
 	DM 	$+ 	$- 	$- 	do 	do 	do 	) 	$- 	7 	H  	G!" 	s8}}# r   c                   t          |                     d                    }|st          d          S 	 t                      \  }}	 |                    ||          }|'t          d| d          |                                 S |                    ||          }|                    ||          }|                    ||          }|	                    ||          }	|
                    ||          }
d }d t          j         ||          |	|
d |D             d	 |d
d         D             fd|D             |                    ||          d          |                                 S # |                                 w xY w# t          $ r6}t                              d           t          d|           cY d}~S d}~ww xY w)zsRead a task's full state: task row, parents, children, comments,
    runs (attempt history), and the last N events.r%   :task_id is required (or set HERMES_KANBAN_TASK in the env)Nztask z
 not foundc                    | j         | j        | j        | j        | j        | j        | j        | j        | j        | j	        | j
        | j        | j        | j        | j        dS )NrY   rZ   bodyr[   r\   r^   r]   r_   r`   ra   rb   rc   rd   resultre   rs   )ts    r   
_task_dictz _handle_show.<locals>._task_dict   sZ    $!& !
ahhAJ&'&6&'&6"#,al"#,$%Nh&'&6  r   c           
     t    | j         | j        | j        | j        | j        | j        | j        | j        | j        d	S )N	rY   profiler\   outcomesummaryerrormetadatarc   ended_atry   )rs    r   	_run_dictz_handle_show.<locals>._run_dict  s:    $19h19 y17 !
"#,AJ  r   c                8    g | ]}|j         |j        |j        d S )authorrt   rb   r   .0cs     r   
<listcomp>z _handle_show.<locals>.<listcomp>  s?          !x#$<1 1  r   c                D    g | ]}|j         |j        |j        |j        d S )kindpayloadrb   run_idr   )r   es     r   r   z _handle_show.<locals>.<listcomp>  sE         V	#$<18E E  r   ic                &    g | ]} |          S r   r   )r   r   r   s     r   r   z _handle_show.<locals>.<listcomp>  s!    444!1444r   )rn   rf   rg   commentseventsrunsworker_contextzkanban_show failedzkanban_show: )r$   r   r   r7   get_taskcloselist_commentslist_events	list_runsrj   rk   r;   r<   build_worker_contextr   logger	exception)rH   kwr.   r6   rm   rn   r   r   r   rf   rg   rw   r   r   s                @r   _handle_showr      s2    488I..
/
/C 
H
 
 	
</::D7	;;tS))D|!"9#"9"9"9::h JJLLLLg ''c22H^^D#..F<<c**DmmD#..G||D#..H     :"
4(("$  &  
  $CDD\  
 5444t444
 #%"9"9$"D"D'   , JJLLLLDJJLLLL / / /-...-!--......../sB   F	 *E0 2F	 CE0 F	 0FF	 	
G	+G>G	G	c           
        t          d          }|r|S |                     d          }|                     d          }|                     d          }t          | d          \  }}|rt          |          S |                     d          }|t          }	 t          |          }n&# t          t          f$ r t          d          cY S w xY w|d	k     rt          d
          S |t          k    rt          dt                     S 	 t                      \  	 
                              }	                    |||||d	z             }
t          |
          |k    }|
d|         }t          j        fd|D             t          |          |||r#|t          k     rt          |dz  t                    nd|	d                                           S #                                  w xY w# t          $ r}t          d|           cY d}~S d}~wt"          $ r6}t$                              d           t          d|           cY d}~S d}~ww xY w)z:List task summaries with the same core filters as the CLI.kanban_listr[   r\   r^   include_archivedlimitNzlimit must be an integer   zlimit must be >= 1zlimit must be <= r[   r\   r^   r   r   c                2    g | ]}t          |          S r   )ro   )r   rv   rm   r6   s     r   r   z _handle_list.<locals>.<listcomp>U  s&    IIIa,Rq99IIIr      )taskscountr   	truncated
next_limitpromotedzkanban_list: zkanban_list failed)rV   r   rS   r   KANBAN_LIST_DEFAULT_LIMITr*   	TypeErrorr+   KANBAN_LIST_MAX_LIMITr7   recompute_ready
list_tasksrl   r;   r<   minr   r   r   r   )rH   r   guardr[   r\   r^   r   
bool_errorr   r   rowsr   r   r   rm   r6   s                 @@r   _handle_listr   ,  s   &}55E xx
##HXXhFXXhF#249K#L#L j &*%%%HHWE})6E

z" 6 6 64555556qyy.///$$$E.CEEFFF#/::D	 ))$//H ==!!1ai !  D D		E)I%LE:IIIII5IIIU& !M%*-B%B%B 	#8999HL$
 
 
 
 JJLLLLDJJLLLL / / /-!--........ / / /-...-!--......../s[   B( ( C
CG/ B)G G/ G,,G/ /
I9H
II+IIIc                X   t          |                     d                    }|st          d          S t          |          }|r|S |                     d          }|                     d          }|                     d          }|                     d          }|dt	          |t
                    r|g}t	          |t          t          f          s$t          dt          |          j	                   S d	 |D             }|s|st          d
          S |9t	          |t                    s$t          dt          |          j	                   S 	 t                      \  }}		 	 |                    |	|||||t          |                    }
nV# |j        $ rI}t          dd                    |j                   d          cY d}~|	                                 S d}~ww xY w|
s't          d| d          |	                                 S |                    |	|          }t'          ||r|j        nd          |	                                 S # |	                                 w xY w# t*          $ r6}t,                              d           t          d|           cY d}~S d}~ww xY w)z5Mark the current task done with a structured handoff.r%   rq   r|   r~   ru   created_cardsNz.created_cards must be a list of task ids, got c                    g | ]D}t          |                                          #t          |                                          ES r   )r&   rC   r   s     r   r   z$_handle_complete.<locals>.<listcomp>  sI     
 
 
 SVV\\^^
FFLLNN
 
 
r   z4provide at least one of: summary (preferred), resultz%metadata must be an object/dict, got )ru   r|   r~   r   expected_run_idzfkanban_complete blocked: the following created_cards do not exist or were not created by this worker: z, z. Your task is still in-flight (no state change). Retry kanban_complete with the same summary/metadata and either drop these ids from created_cards, or pass created_cards=[] to skip the card-claim check entirely.zcould not complete z! (unknown id or already terminal)r%   r   zkanban_complete failedzkanban_complete: )r$   r   r   r1   rR   r&   listtupletype__name__rI   r7   complete_taskr-   HallucinatedCardsErrorjoinphantomr   
latest_runr=   rY   r   r   r   )rH   r   r.   ownership_errr|   r~   ru   r   r6   rm   r:   hall_errrunr   s                 r   _handle_completer   h  s8   
488I..
/
/C 
H
 
 	
 3377M hhy!!Gxx
##HXXhFHH_--M mS)) 	,*OM-$77 	2&&/2 2  

 
$1
 
 
  
v 
B
 
 	
 Jx$>$>MDNN4KMM
 
 	
(3::D#	%%#!7X"/$23$7$7	 &   ,    "Oyy!122O O O        JJLLLL7(  !P#PPP  JJLLLL --c**CsS+B366dCCCJJLLLLDJJLLLL 3 3 312221a11222222223sr   I) #)F I 
G *GG I I) G  I 7I) /I ;I) I&&I) )
J)3+J$J)$J)c                    t          |                     d                    }|st          d          S t          |          }|r|S |                     d          }|r!t	          |                                          st          d          S 	 t                      \  }}	 |                    |||t          |                    }|s't          d| d          |	                                 S |
                    ||          }t          ||r|j        nd	          |	                                 S # |	                                 w xY w# t          $ r6}	t                              d
           t          d|	           cY d}	~	S d}	~	ww xY w)z?Transition the task to blocked with a reason a human will read.r%   rq   reasonu2   reason is required — explain what input you need)r   r   zcould not block z% (unknown id or not in running/ready)Nr   zkanban_block failedzkanban_block: )r$   r   r   r1   r&   rC   r7   
block_taskr-   r   r   r=   rY   r   r   r   )
rH   r   r.   r   r   r6   rm   r:   r   r   s
             r   _handle_blockr     s   
488I..
/
/C 
H
 
 	
 3377M XXhF PV**,, PNOOO0::D	c .s 3 3   B
  !&s & & &  JJLLLL --c**CsS+B366dCCCJJLLLLDJJLLLL 0 0 0.///.1..////////0sB   E !:D4 E 0/D4 E 4E

E 
F+FFFc                   t          |                     d                    }|st          d          S t          |          }|r|S |                     d          }	 t	                      \  }}	 t
          j                            d          }|                    |||           |                    |||t          |                    }|s't          d| d          |
                                 S t          |	          |
                                 S # |
                                 w xY w# t          $ r6}	t                              d
           t          d|	           cY d}	~	S d}	~	ww xY w)u  Signal that the worker is still alive during a long operation.

    Extends the claim TTL via ``heartbeat_claim`` AND records a heartbeat
    event via ``heartbeat_worker``. Without the ``heartbeat_claim`` half,
    a diligent worker that loops this tool while a single tool call
    blocks the agent for >DEFAULT_CLAIM_TTL_SECONDS still gets reclaimed
    by ``release_stale_claims`` — which is exactly the trap that
    ``heartbeat_claim``'s docstring warns against.
    r%   rq   noteHERMES_KANBAN_CLAIM_LOCK)claimer)r   r   zcould not heartbeat z (unknown id or not running))r%   zkanban_heartbeat failedzkanban_heartbeat: N)r$   r   r   r1   r7   r   r   heartbeat_claimheartbeat_workerr-   r   r=   r   r   r   )
rH   r   r.   r   r   r6   rm   
claim_lockr:   r   s
             r   _handle_heartbeatr     s    488I..
/
/C 
H
 
 	
 3377M 88FD4::D	 (BCCJtS*===$$ .s 3 3	 %  B  !L3LLL 
 JJLLLL s###JJLLLLDJJLLLL 4 4 423332q22333333334sC   D2 /A1D  D2 5D D2 D//D2 2
E2<+E-'E2-E2c                   |                      d          }|st          d          S |                      d          }|r!t          |                                          st          d          S t          j                             d          pd}	 t                      \  }}	 |                    |||t          |                    }t          ||          |	                                 S # |	                                 w xY w# t          $ r6}t                              d	           t          d
|           cY d}~S d}~ww xY w)z$Append a comment to a task's thread.r%   uo   task_id is required (use the current task id if that's what you mean — pulls from env but kept explicit here)rt   zbody is requiredHERMES_PROFILEworker)r   rt   )r%   
comment_idzkanban_comment failedzkanban_comment: N)r   r   r&   rC   r   r   r7   add_commentr=   r   r   r   r   )	rH   r   r.   rt   r   r6   rm   cidr   s	            r   _handle_commentr   	  sP   
((9

C 
B
 
 	
 88FD .s4yy(( .,--- Z^^,--9F	2::D	..s6D		.JJCss333JJLLLLDJJLLLL 2 2 201110Q00111111112s6   D "6C- D -DD 
E+E;EEc                J   |                      d          }|r!t          |                                          st          d          S |                      d          }|st          d          S |                      d          }|                      d          pg }|                      d          pt          j                             d          }|                      d	          }|                      d
          pd}|                      d          }	t          | d          \  }
}|rt          |          S |                      d          }|                      d          }|                      d          }t          |t                    r|g}|@t          |t          t          f          s$t          dt          |          j                   S t          |t                    r|g}t          |t          t          f          s$t          dt          |          j                   S 	 t                      \  }}	 |                    |t          |                                          |t          |          t          |          ||t          |          ndt          |          |	|
||t          |          nd|t          j                             d          pd          }|                    ||          }t!          ||r|j        nd          |                                 S # |                                 w xY w# t&          $ r}t          d|           cY d}~S d}~wt(          $ r6}t*                              d           t          d|           cY d}~S d}~ww xY w)zCreate a child task. Orchestrator workers use this to fan out.

    ``parents`` can be a list of task ids; dependency-gated promotion
    works as usual.
    rZ   ztitle is requiredr[   u   assignee is required — name the profile that should execute this task (the dispatcher will only spawn tasks with an assignee)rt   rf   r^   HERMES_TENANTr]   r_   scratchr`   triageidempotency_keymax_runtime_secondsskillsNz*skills must be a list of skill names, got z(parents must be a list of task ids, got r   r   r   )rZ   rt   r[   rf   r^   r]   r_   r`   r   r   r   r   ra   r%   r\   zkanban_create: zkanban_create failed)r   r&   rC   r   r   r   rS   rR   r   r   r   r   r7   create_taskr*   r   r=   r\   r   r+   r   r   r   )rH   r   rZ   r[   rt   rf   r^   r]   r_   r`   r   r   r   r   r   r6   rm   new_tidnew_taskr   s                       r   _handle_creater   *  s    HHWE /E

((** /-...xx
##H 
K
 
 	
 88FDhhy!!'RGXXhB2:>>/#B#BFxx
##HXX.//<9NXX.//N(x88FJ &*%%%hh011O((#899XXhF&# *VdE]"C"CPf9NPP
 
 	
 '3 )ge}-- 
OtG}}7MOO
 
 	
!1::D	nn%jj&&((Xg*2*>XA">22- / +6 +,,,<@:>>*:;;Gx# %  G& {{411H*2<x  
 JJLLLLDJJLLLL 1 1 1/A//00000000 1 1 1/000/A//000000001sI   %L> 7CL% L> %L;;L> >
N"MN"N",+NN"N"c                   t          d          }|r|S |                     d          }|st          d          S t          t	          |                    }|r|S 	 t                      \  }}	 |                    |t	          |                    }|s't          d| d          |                                 S t          t	          |          d          |                                 S # |                                 w xY w# t          $ r6}t                              d           t          d	|           cY d
}~S d
}~ww xY w)z(Transition a blocked task back to ready.kanban_unblockr%   ztask_id is requiredzcould not unblock z (not blocked or unknown)readyr   zkanban_unblock failedzkanban_unblock: N)rV   r   r   r1   r&   r7   unblock_taskr   r=   r   r   r   )	rH   r   r   r.   r   r6   rm   r:   r   s	            r   _handle_unblockr   v  sZ   &'788E 
((9

C 1/00023s88<<M 2::D	s3xx00B W!"Us"U"U"UVV JJLLLL s3xx888JJLLLLDJJLLLL 2 2 201110Q00111111112sB   D -7C+ $D 9C+ D +DD 
E+D?9E?Ec                   |                      d          }|                      d          }|r|st          d          S 	 t                      \  }}	 |                    |||           t	          ||          |                                 S # |                                 w xY w# t          $ r}t          d|           cY d}~S d}~wt          $ r6}t          	                    d           t          d|           cY d}~S d}~ww xY w)u4   Add a parent→child dependency edge after the fact.	parent_idchild_idz(both parent_id and child_id are requiredr   r   zkanban_link: Nzkanban_link failed)
r   r   r7   
link_tasksr=   r   r+   r   r   r   )rH   r   r   r   r6   rm   r   s          r   _handle_linkr     s:   %%Ixx
##H FH FDEEE/::D	MM$)hMGGGX>>>JJLLLLDJJLLLL / / /-!--........ / / /-...-!--......../sG   B' (B 9B' B$$B' '
D1CDD+D DDzrTask id. If omitted, defaults to HERMES_KANBAN_TASK from the env (the task the dispatcher spawned you to work on).kanban_showuO  Read a task's full state — title, body, assignee, parent task handoffs, your prior attempts on this task if any, comments, and recent events. Use this to (re)orient yourself before starting work, especially on retries. The response includes a pre-formatted ``worker_context`` string suitable for inclusion verbatim in your reasoning.objectstring)r   description)r   
propertiesrequired)rJ   r   
parametersr   u  List Kanban task summaries so an orchestrator profile can discover work to route. Supports the same core filters as the CLI: assignee, status, tenant, include_archived, and limit. Returns compact rows with ids, title, status, assignee, priority, parent/child ids, and counts. Bounded to 50 rows by default, 200 max, with truncation metadata. Also recomputes ready tasks before listing, matching the CLI. Orchestrator-only — dispatcher-spawned task workers never see this tool.z!Optional assignee/profile filter.)r   todor   runningblockeddonearchivedzOptional task status filter.)r   enumr   z)Optional tenant/project namespace filter.booleanz*Include archived tasks. Defaults to false.integerz6Optional maximum rows to return (default 50, max 200).r   kanban_completeu  Mark your current task done with a structured handoff for downstream workers and humans. Prefer ``summary`` for a human-readable 1-3 sentence description of what you did; put machine-readable facts in ``metadata`` (changed_files, tests_run, decisions, findings, etc). At least one of ``summary`` or ``result`` is required. If you created new tasks via ``kanban_create`` during this run, list their ids in ``created_cards`` — the kernel verifies them so phantom references are caught before they leak into downstream automation.zrHuman-readable handoff, 1-3 sentences. Appears in Run History on the dashboard and in downstream workers' context.u   Free-form dict of structured facts about this attempt — {"changed_files": [...], "tests_run": 12, "findings": [...]}. Surfaced to downstream workers alongside ``summary``.zShort result log line (legacy field, maps to task.result). Use ``summary`` instead when possible; this exists for compatibility with callers that still set --result on the CLI.arrayr   u  Optional structured manifest of task ids you created via ``kanban_create`` during this run. The kernel verifies each id exists and was created by this worker's profile; any phantom id blocks the completion with an error listing what went wrong (auditable in the task's events). Only list ids you got back from a successful ``kanban_create`` call — do not invent or remember ids from prose. Omit the field if you did not create any cards.)r   itemsr   )r%   r|   r~   ru   r   kanban_blocku   Transition the task to blocked because you need human input to proceed. ``reason`` will be shown to the human on the board and included in context when someone unblocks you. Use for genuine blockers only — don't block on things you can resolve yourself.zWhat you need answered, in one or two sentences. Don't paste the whole conversation; the human has the board and can ask follow-ups via comments.)r%   r   r   kanban_heartbeatu   Signal that you're still alive during a long operation (training, encoding, large crawls). Call every few minutes so humans see liveness separately from PID checks. Pure side effect — no work changes.zHOptional short note describing current progress. Shown in the event log.)r%   r   kanban_commentu   Append a comment to a task's thread. Use for durable notes that should outlive this run (questions for the next worker, partial findings, rationale). Ephemeral reasoning doesn't belong here — use your normal response instead.uW   Task id. Required (may be your own task or another's — comment threads are per-task).z Markdown-supported comment body.)r%   rt   rt   kanban_createuc  Create a new kanban task, optionally as a child of the current one (pass the current task id in ``parents``). Used by orchestrator workers to fan out — decompose work into child tasks with specific assignees, link them into a pipeline, then complete your own task. The dispatcher picks up the new tasks on its next tick and spawns the assigned profiles.zShort task title (required).u   Profile name that should execute this task (e.g. 'researcher-a', 'reviewer', 'writer'). Required — tasks without an assignee are never dispatched.zkOpening post: full spec, acceptance criteria, links. The assigned worker reads this as part of its context.zParent task ids. The new task stays in 'todo' until every parent reaches 'done'; then it auto-promotes to 'ready'. Typical fan-in: list all the researcher task ids when creating a synthesizer task.zUOptional namespace for multi-project isolation. Defaults to HERMES_TENANT env if set.zZDispatcher tiebreaker. Higher = picked sooner when multiple ready tasks share an assignee.)r   dirworktreezWorkspace flavor: 'scratch' (fresh tmp dir, default), 'dir' (shared directory, requires absolute workspace_path), 'worktree' (git worktree).zYAbsolute path for 'dir' or 'worktree' workspace. Relative paths are rejected at dispatch.u   If true, task lands in 'triage' instead of 'todo' — a specifier profile is expected to flesh out the body before work starts.zIf a non-archived task with this key already exists, return that task's id instead of creating a duplicate. Useful for retry-safe automation.zxPer-task runtime cap. When exceeded, the dispatcher SIGTERMs the worker and re-queues the task with outcome='timed_out'.u4  Skill names to force-load into the dispatched worker (in addition to the built-in kanban-worker skill). Use this to pin a task to a specialist context — e.g. ['translation'] for a translation task, ['github-code-review'] for a reviewer task. The names must match skills installed on the assignee's profile.)rZ   r[   rt   rf   r^   r]   r_   r`   r   r   r   r   rZ   r[   r   u   Move a blocked Kanban task back to ready. Orchestrator-only — only profiles with the kanban toolset can unblock routed work; dispatcher-spawned task workers never see this tool.z#Blocked task id to return to ready.kanban_linku   Add a parent→child dependency edge after both tasks already exist. The child won't promote to 'ready' until all parents are 'done'. Cycles and self-links are rejected.zParent task id.zChild task id.r   r   r   r   u   📋)rJ   toolsetschemahandlercheck_fnemojiu   ✔u   ⏸u   💓u   💬u   ➕u   ▶u   🔗)r
   r   )r    r!   r
   r!   )r%   r&   r
   r'   )r.   r&   r
   r!   )r8   r   r
   r&   )r>   r   r
   r!   )rH   rI   rJ   r&   rG   r   )rT   r&   r
   r!   )r
   rW   )rH   rI   r
   r&   )1__doc__
__future__r   r;   loggingr   typingr   r   tools.registryr   r   	getLoggerr   r   r   r   r   r   r   r$   r-   r1   r7   r=   rF   rS   rV   ro   r   r   r   r   r   r   r   r   r   _DESC_TASK_ID_DEFAULTKANBAN_SHOW_SCHEMAKANBAN_LIST_SCHEMAKANBAN_COMPLETE_SCHEMAKANBAN_BLOCK_SCHEMAKANBAN_HEARTBEAT_SCHEMAKANBAN_COMMENT_SCHEMAKANBAN_CREATE_SCHEMAKANBAN_UNBLOCK_SCHEMAKANBAN_LINK_SCHEMAregisterr   r   r   <module>r      s   2 # " " " " "   				                 / / / / / / / /		8	$	$   
 
 
 
) ) ) )") ) ) )$   
 
 
 
   @  . . . .    ?D B B B B B B   $   :D/ D/ D/ D/N9/ 9/ 9/ 9/xK3 K3 K3 K3\ 0  0  0  0F-4 -4 -4 -4`2 2 2 2BI1 I1 I1 I1X2 2 2 22/ / / /48  	&  4 
 	 	  . 	  !B 
 !    >  !J 
 "K! !
 "W +
 
4 9 * * Z 		  !4 
 !(  !5  !B    (+	0	 ?/
 /
` e3 3B B J 	  !4 
 !E 
 
 J!   < 	&  !4 
 !. 
 
    8 	<  !C  !A 
 
 '   8 	C  != 
 !"  !#    (+(	
 
 !<  "C  !666K	  !?  "3  !E    "5$ $   (+*	 od
 d
J j)Oh hs s l 	?
  D 
 K	 	  ( 	:
 "*;LMM"*;KLL
 
 !*-   ,  	
     	,
     	!
     	
     	"
     	 
     	
     	 ,
     	
     r   