+
    lHàjÊW  ã                  ó¶  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIHt Rt	]P                  ! R]P                  ! ]	4      ,           R,           ]P                  4      tR R ltR	t]P                   ! 4       t/ tR
]R&   R R ltR R ltR tR R ltR R ltR R ltR R ltROR R lltR R ltR R ltR R  ltROR! R" lltR# R$ lt R% R& lt!R' R( lt"R) R* lt#R+ R, lt$]%! 0 RPm4      t&R- R. lt'R/ R0 lt(R1 R2 lt)R3 R4 lt*R5 R6 lt+R7 R8 lt,R9 R: lt-R; R< lt.ROR=R>/R? R@ lllt/RAt0RBt1RC RD lt2RORE RF llt3RORG RH llt4RORI RJ llt5RORK RL llt6RM RN lt7R# )Quî  Bot Mode roster probe â€” canonical Bot Chat system prompt section.

When any profile carries ``ui_meta['hermes-bots']`` in profile.yaml (Bot-Mode-managed),
a bot's canonical "Bot Chat" session â€” ONLY that session (agent/system_prompt.py enforces
the ``BOT_CHAT_TITLE`` gate) â€” gets a "Messaging other agents" section. Silent (``""``)
when no profile is managed or on any error. Older desktop builds appended a frozen copy of
the section to SOUL.md; ``strip_legacy_protocol`` drops it at load time so the live roster
here is the only copy any session sees. Cached per (process, home) so compression rebuilds
produce identical bytes. Toggle: ``agent.bot_mode_protocol``. Also hosts path/roster
helpers shared by ``bot_mode_dm`` and ``bot_relay``.
)ÚannotationsN)ÚPathz## Messaging other agentsz\n*z[ \t]*\n.*?(?=\n## |\Z)c               ó    € V ^8„  d   QhRRRR/# )é   ÚtextÚstrÚreturn© )Úformats   "Ú9/home/ubuntu/.hermes/hermes-agent/tools/bot_mode_probe.pyÚ__annotate__r      s   € ÷ eñ e ð e¨ñ eó    c                ór   € \         V 9   d,   \        P                  RV 4      P                  4       R,           # T # )zRSOUL text without the plugin-era "## Messaging other agents" section (idempotent).Ú
)Ú_PROTOCOL_HEADINGÚ_LEGACY_PROTOCOL_REÚsubÚstrip)r   s   &r   Ústrip_legacy_protocolr      s2   € äARÐVZÔAZÔ×"Ñ" 4¨Ó.×4Ñ4Ó6¸Õ=ÐdÐ`dÐdr   zBot Chatzdict[str, str]Ú_cachedc               ó   € V ^8„  d   QhRR/# ©r   r   r   r	   )r
   s   "r   r   r   (   s   € ÷ *ñ *�sñ *r   c                 ó.   € ^ RI Hp  \        V ! 4       4      # )zIAmbient process HERMES_HOME (env, else the platform default) as a string.©Úget_process_hermes_home)Úhermes_constantsr   r   r   s    r   Ú_default_homer   (   s   € å8ÜÑ&Ó(Ó)Ð)r   c               ó    € V ^8„  d   QhRRRR/# )r   Úhomeústr | os.PathLike | Noner   r   r	   )r
   s   "r   r   r   .   s   € ÷ 8ñ 8Ð0ð 8°Tñ 8r   c                óV   € \        V '       d   \        V 4      4      # \        4       4      # ©N)r   r   r   ©r   s   &r   Ú_resolve_homer#   .   s   € ÜŸT”�D“	Ó7Ð7¤}£Ó7Ð7r   c                ó8   €  V ! 4       #   \          d    Tu # i ; i)uW   ``fn()`` or ``default`` on any exception â€” the probe must never crash a prompt build.)Ú	Exception)ÚfnÚdefaults   &&r   Ú_swallowr(   2   s"   € ðÙ‹tˆøÜô ØŠðús   ‚	 ‰˜c               ó    € V ^8„  d   QhRRRR/# )r   r   r   r   r	   )r
   s   "r   r   r   :   s   € ÷ Jñ J�tð J ñ Jr   c                óh   € V P                   P                  R8X  d   V P                   P                   # T # )z?Root ~/.hermes for both the default profile and named profiles.Úprofiles©ÚparentÚnamer"   s   &r   Ú_hermes_rootr/   :   s(   € à!%§¡×!1Ñ!1°ZÔ!?ˆ4�;‰;×ÑÐIÀTÐIr   c               ó    € V ^8„  d   QhRRRR/# ©r   r   r   r   r   r	   )r
   s   "r   r   r   ?   s   € ÷ Fñ F˜ð F ñ Fr   c                óT   € V P                   P                  R 8X  d   V P                  # R# )r+   r'   r,   r"   s   &r   Ú_profile_namer3   ?   s"   € ØŸ™×(Ñ(¨JÔ6ˆ4�9‰9ÐE¸IÐEr   c               ó    € V ^8„  d   QhRRRR/# )r   r.   r   r   r	   )r
   s   "r   r   r   C   s   € ÷ 3ñ 3�#ð 3˜#ñ 3r   c                ó   € V R 8X  d   R# T # )r'   Úhermesr	   )r.   s   &r   Ú_handler7   C   s   € à˜yÔ(ˆ8Ð2¨dÐ2r   c               ó    € V ^8„  d   QhRRRR/# )r   Úrootr   r   zlist[tuple[str, Path]]r	   )r
   s   "r   r   r   H   s   € ÷ 'ñ '�$ð 'Ð1ñ 'r   c                ó\   aaa€ ^ RI HoHo V R,          o\        VVV3R l. 4      pRV 3.VO# )ud  (name, dir) for the default profile + every live named profile, sorted. Same identity
predicate as ``profile list``: infra dirs (``sessions/``, ``logs/``) and tombstones are not
teammates (#99392), and neither is a marker-carrying dir whose name is not a profile id â€”
a parked backup or staging dir must never become a ``message_agent`` target (#116905).)ÚPROFILE_ID_REÚnamed_profile_is_liver+   c                 ó4  <€ SP                  4       '       d|   \        SP                  4       4       U u. uFW  p V P                  R 8w  g   K  SP	                  V P                  4      '       g   K9  S! V 4      '       g   KI  V P                  V 3NKY  	  up # . # u up i )r'   )Úis_dirÚsortedÚiterdirr.   Úmatch)Úcr;   r<   r+   s    €€€r   Ú<lambda>Ú_roster.<locals>.<lambda>Q   sŒ   ø€ ð
 �?‰?×Òô ˜H×,Ñ,Ó.Ô/ó
á/�Ø�v‰v˜Ñ"ô à'4×':Ñ':¸1¿6¹6×'Bô áG\Ð]^×G_ô ˆQ�V‰V�Q‹KÙ/ñ
ð ð ðùò 
s   ³BÁBÁ.BÁ>Br'   )r   r;   r<   r(   )r9   Únamedr;   r<   r+   s   & @@@r   Ú_rosterrF   H   s<   ú€ ÷
 Fà�jÕ €HÜö	ð 	ó	€Eð ˜ÐÐ& Ð&Ð&r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úpathr   Úneedlez
str | Noner   údict | Noner	   )r
   s   "r   r   r   ]   s!   € ÷ !ñ !˜$ð !¨
ð !¸kñ !r   c                ó,   a a€ VV 3R lp\        VR4      # )z­YAML mapping at ``path``, or None when missing / not a mapping / unreadable. ``needle``:
cheap substring precheck that skips the YAML parse on the dominant (unmanaged) path.c                 óÒ   <€ SP                  4       '       g   R # SP                  RRR7      p Se
   SV 9  d   R # ^ R IpVP                  V 4      p\	        V\
        4      '       d   V# R # )Nz	utf-8-sigÚreplace)ÚencodingÚerrors)Úis_fileÚ	read_textÚhermes_yamlÚ	safe_loadÚ
isinstanceÚdict)ÚrawÚyamlÚdatarI   rH   s      €€r   Ú_loadÚ_read_yaml_dict.<locals>._load`   s[   ø€ Ø�|‰|�~Š~ÙØ�n‰n k¸)ˆnÓDˆØÒ &°Ô"3ÙÛ"à�~‰~˜cÓ"ˆÜ! $¬×-Ò-ˆtÐ7°4Ð7r   N©r(   )rH   rI   rY   s   ff r   Ú_read_yaml_dictr\   ]   s   ù€ ö	8ô �E˜4Ó Ð r   c               ó    € V ^8„  d   QhRRRR/# )r   rX   rJ   r   r	   )r
   s   "r   r   r   n   s   € ÷ 4ñ 4�[ð 4 [ñ 4r   c                ó¾   € V '       d   V P                  R4      MRp\        V\        4      '       d   VP                  R4      MRp\        V\        4      '       d   V# R# )zIThe ``ui_meta['hermes-bots']`` block of a parsed profile.yaml, if a dict.Úui_metaNúhermes-bots)ÚgetrT   rU   )rX   r_   Úbotss   &  r   Ú
_bots_metarc   n   sG   € ç%)ˆd�h‰h�yÔ!¨t€GÜ)3°G¼T×)BÒ)Bˆ7�;‰;�}Ô%È€DÜ˜d¤D×)Ò)ˆ4Ð3¨tÐ3r   c               ó    € V ^8„  d   QhRRRR/# )r   Úprofile_dirr   r   Úboolr	   )r
   s   "r   r   r   u   s   € ÷ `ñ ` ð `¨$ñ `r   c                ó>   € \        \        V R ,          R4      4      RJ# )úprofile.yamlr`   N)rc   r\   )re   s   &r   Ú_is_bot_managedri   u   s   € Ü”o k°NÕ&BÀMÓRÓSÐ[_Ð_Ð_r   c               ó    € V ^8„  d   QhRRRR/# )r   r9   r   r   rf   r	   )r
   s   "r   r   r   y   s   € ÷ >ñ >�tð > ñ >r   c                óŽ   € \         ;QJ d%    R  \        V 4       4       F  '       g   K   R# 	  R# ! R  \        V 4       4       4      # )c              3  ó<   "  € T F  w  r\        V4      x € K  	  R # 5ir!   ©ri   )Ú.0Ú_nÚds   &  r   Ú	<genexpr>Ú_any_managed.<locals>.<genexpr>z   s   é € Ð=©}¡e bŒ˜q×!Ð!«}ùs   ‚TF)ÚanyrF   )r9   s   &r   Ú_any_managedrt   y   s3   € ß‹3Ñ=¬w°t¬}Ó=�3Œ3Ð=Š3Ð=ˆ3Ñ=¬w°t¬}Ó=Ó=Ð=r   c               ó    € V ^8„  d   QhRRRR/# )r   r   r   r   rf   r	   )r
   s   "r   r   r   }   s   € ÷ Tñ TÐ6ð TÀ$ñ Tr   c                ó$   a € \        V 3R lR4      # )u  True when ANY profile on this install is Bot-Mode-managed. Never raises. The
``message_agent`` injection gate â€” deliberately independent of the protocol section's
emptiness: a SOUL.md carrying the legacy protocol gets an empty section but still gets the tool.c                 ó>   <€ \        \        \        S 4      4      4      # r!   )rt   r/   r#   r"   s   €r   rC   Ú%is_bot_mode_managed.<locals>.<lambda>�   s   ø€ œL¬´mÀDÓ6IÓ)JÔKr   Fr[   r"   s   fr   Úis_bot_mode_managedry   }   s   ø€ ô ÔKÈUÓSÐSr   c               ó    € V ^8„  d   QhRRRR/# )r   Úpartsr   r   r	   )r
   s   "r   r   r   „   s   € ÷ /ñ /�sð /˜sñ /r   c                 ó2   € RP                  R V  4       4      # )uH   'title â€” description' from the non-empty parts (either may be absent).u    â€” c              3  ó8   "  € T F  q'       g   K  Vx € K  	  R # 5ir!   r	   ©rn   Úps   & r   rq   Ú_role_line.<locals>.<genexpr>†   s   é € Ð.¡5˜a«AŸš£5ùó   ‚	�
)Újoin)r{   s   *r   Ú
_role_linerƒ   „   s   € à�<‰<Ñ.¡5Ó.Ó.Ð.r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úhandler   r{   r   r	   )r
   s   "r   r   r   ‰   s!   € ÷ /ñ /�Cð / ð /¨ñ /r   c                ó$   € \        RV  R2.VO5!  # )uC   Roster line: '- `handle`' plus ' â€” part' for each non-empty part.z- `Ú`)rƒ   )r…   r{   s   &*r   Ú_bulletrˆ   ‰   s   € ä˜˜F˜8 1�oÐ.¨Ó.Ð.r   c               ó    € V ^8„  d   QhRRRR/# )r   re   r   r   r   r	   )r
   s   "r   r   r   Ž   s   € ÷ ñ ˜tð ¨ñ r   c                ó.   a € R V 3R llp\        VR4      # )uv  Teammate role line: Bot Mode title â€” profile description; tells a teammate
WHO to message for a job. A friendly ``display_name`` (``hermes profile rename``) that
differs from both the folder id and the title leads the line, so an untagged
"talk to Scribe" maps to the folder handle without a disk search (#100671).
Single-line, â‰¤160 chars, "" when nothing. Never raises.c               ó   € V ^8„  d   QhRR/# r   r	   )r
   s   "r   r   Ú#_profile_role.<locals>.__annotate__”   s   € ÷ ,ñ ,�3ñ ,r   c            	     ól  <€ \        SR ,          4      ;'       g    / p \        \        V 4      ;'       g    / P                  R4      ;'       g    R4      P	                  4       p\        V P                  R4      ;'       g    R4      P	                  4       pVP                  4       SP                  P                  4       VP                  4       39   d   Rp\        Y!\        V P                  R4      ;'       g    R4      P	                  4       4      pRP                  VP                  4       4      R,          # )rh   ÚtitleÚ Údisplay_nameÚdescriptionÚ :Né    N)
r\   r   rc   ra   r   Úlowerr.   rƒ   r‚   Úsplit)rX   rŽ   ÚdisplayÚlinere   s       €r   Ú_roleÚ_profile_role.<locals>._role”   sã   ø€ Ü˜{¨^Õ;Ó<×BÐBÀˆÜ”Z Ó%×+Ð+¨×0Ñ0°Ó9×?Ð?¸RÓ@×FÑFÓHˆÜ�d—h‘h˜~Ó.×4Ð4°"Ó5×;Ñ;Ó=ˆØ�=‰=‹?˜{×/Ñ/×5Ñ5Ó7¸¿¹»ÐGÔGØˆGÜ˜'¬#¨d¯h©h°}Ó.E×.KÐ.KÈÓ*L×*RÑ*RÓ*TÓUˆØ�x‰x˜Ÿ
™
›Ó% dÕ+Ð+r   r�   r[   )re   r˜   s   f r   Ú_profile_rolerš   Ž   s   ø€ ÷,ð ,ô �E˜2ÓÐr   c               ó    € V ^8„  d   QhRRRR/# )r   re   r   r   útuple[str, str]r	   )r
   s   "r   r   r       s   € ÷ %ñ % ð %¨/ñ %r   c                ó.   a € R V 3R llp\        VR4      # )z[(Bot Mode title, profile.yaml ``display_name``) for a profile, "" when unset. Never raises.c               ó   € V ^8„  d   QhRR/# )r   r   rœ   r	   )r
   s   "r   r   Ú%_friendly_names.<locals>.__annotate__¢   s   € ÷ =ñ =�?ñ =r   c                 ó*  <€ \        SR ,          4      ;'       g    / p \        \        V 4      ;'       g    / P                  R4      ;'       g    R4      P	                  4       \        V P                  R4      ;'       g    R4      P	                  4       3# )rh   rŽ   r�   r�   )r\   r   rc   ra   r   )rX   re   s    €r   Ú_readÚ_friendly_names.<locals>._read¢   sw   ø€ Ü˜{¨^Õ;Ó<×BÐBÀˆÜ”Z Ó%×+Ð+¨×0Ñ0°Ó9×?Ð?¸RÓ@×FÑFÓHÜ�D—H‘H˜^Ó,×2Ð2°Ó3×9Ñ9Ó;ð=ð 	=r   )r�   r�   r[   )re   r¡   s   f r   Ú_friendly_namesr£       s   ø€ ÷=ð =ô
 �E˜8Ó$Ð$r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r.   r   re   r   r   r	   )r
   s   "r   r   r   ª   s&   € ÷ Wñ W˜ð W¨$ð W°3ñ Wr   c                ó`   € \        R \        V4       4       R4      ;'       g    \        V 4      # )uÿ   Human-facing sender name, in the Desktop's ``botFriendlyNames`` order: Bot Mode title,
then profile.yaml ``display_name`` (``hermes profile rename``), else the @handle â€” the
renamed primary signs as ``Maia (@hermes)``, not ``hermes (@hermes)`` (#89720).c              3  ó8   "  € T F  q'       g   K  Vx € K  	  R # 5ir!   r	   ©rn   Úns   & r   rq   Ú _display_name.<locals>.<genexpr>®   s   é € Ð>Ñ8�q»A—’Ó8ùr�   N)Únextr£   r7   )r.   re   s   &&r   Ú_display_namer«   ª   s)   € ô Ñ>œO¨KÔ8Ó>ÀÓE×VÐVÌÐQUËÐVr   c               ó    € V ^8„  d   QhRRRR/# )r   Úvaluer   r   úset[str]r	   )r
   s   "r   r   r   µ   s   € ÷ ]ñ ]�sð ]˜xñ ]r   c                ó~  € \        T ;'       g    R4      P                  4       P                  4       p\        P                  ! RRV4      P                  R4      p\        P                  ! RRV4      pW#3 Uu0 uF;  pV'       g   K  \        P
                  ! RV4      '       g   K,  V\        9  g   K9  VkK=  	  up# u upi )uç   Lower-cased mention forms of a friendly name, mirroring the Desktop's
``mentionNameForms``: slugified (``"Dr. Foo"`` â†’ ``dr-foo``, what autocomplete inserts)
and collapsed (``drfoo``). Reserved tokens and empty forms are dropped.r�   z[^a-z0-9_-]+Ú-z[a-z0-9][a-z0-9_-]*)r   r   r”   Úrer   Ú	fullmatchÚ_RESERVED_ALIASES)r­   r.   ÚslugÚ	collapsedÚfs   &    r   Úalias_formsr·   µ   s¨   € ô ˆu�{ˆ{˜Ó×!Ñ!Ó#×)Ñ)Ó+€DÜ�6Š6�/ 3¨Ó-×3Ñ3°CÓ8€DÜ—’�¨¨DÓ1€IØÑ(ó ]Ñ(�!Üô Ü—\’\Ð"8¸!×<ô ØABÔJ[ÑA[÷ ˆAÑ(ñ ]ð ]ùò ]s   Á6
B:ÂB:Â$B:Â1B:c               ó    € V ^8„  d   QhRRRR/# )r   r9   r   r   údict[str, set[str]]r	   )r
   s   "r   r   r   À   s   € ÷  ñ  ˜$ð  Ð#6ñ  r   c                ó.   a € R V 3R llp\        V/ 4      # )u±  ``alias form â†’ {folder ids}`` for every local profile's friendly names (profile.yaml
``display_name`` and the Bot Mode title). Folder ids themselves are not aliases: the
caller matches those first, so a target that is an exact folder id always addresses that
folder â€” a friendly name colliding with ANOTHER folder id never steals it. Ambiguity
(one alias form shared by several profiles) surfaces as a multi-id set. Never raises.c               ó   € V ^8„  d   QhRR/# )r   r   r¹   r	   )r
   s   "r   r   Ú%local_alias_map.<locals>.__annotate__Æ   s   € ÷ ñ Ð'ñ r   c                 óä   <€ / p \        S4       F]  w  r\        4       P                  ! R  \        V4       4       !   F,  pV P	                  V\        4       4      P                  V4       K.  	  K_  	  V # )c              3  ó8   "  € T F  p\        V4      x € K  	  R # 5ir!   )r·   )rn   r¶   s   & r   rq   Ú2local_alias_map.<locals>._build.<locals>.<genexpr>É   s   é € Ð%[Ñ>Z¸¤k°!§n nÓ>Zùs   ‚)rF   ÚsetÚunionr£   Ú
setdefaultÚadd)Úaliasesr.   re   Úformr9   s       €r   Ú_buildÚlocal_alias_map.<locals>._buildÆ   s^   ø€ Ø')ˆÜ!(¨¦ÑˆDÜ›ŸšÑ%[¼oÈkÔ>ZÓ%[Ô\�Ø×"Ñ" 4¬«Ó/×3Ñ3°DÖ9ó ]ñ "/ð ˆr   r[   )r9   rÆ   s   f r   Úlocal_alias_maprÈ   À   s   ø€ ÷ð ô �F˜BÓÐr   c               ó    € V ^8„  d   QhRRRR/# )r   r9   r   r   ú	list[str]r	   )r
   s   "r   r   r   Ð   s   € ÷  ñ  �ð  ˜)ñ  r   c                ó.   a € R V 3R llp\        V. 4      # )z Registered peer gateway names (``hermes peer``) from config.yaml, read
directly (no config-loader import; the section is absent on most installs). Never raises.c               ó   € V ^8„  d   QhRR/# ©r   r   rÊ   r	   )r
   s   "r   r   Ú_peers.<locals>.__annotate__Ó   s   € ÷ bñ b�Iñ br   c                 ó°   <€ \        SR ,          R4      ;'       g    / P                  R4      p \        V \        4      '       d   \	        R V  4       4      # . # )zconfig.yamlÚ	bot_peersc              3  óz   "  € T F1  p\        V4      P                  4       '       g   K$  \        V4      x € K3  	  R # 5ir!   )r   r   r§   s   & r   rq   Ú)_peers.<locals>._names.<locals>.<genexpr>Õ   s$   é € Ð>¡e ¬s°1«v¯|©|¯~”f”c˜!—f�f£eùs   ‚!;¨;)r\   ra   rT   rU   r?   )Úpeersr9   s    €r   Ú_namesÚ_peers.<locals>._namesÓ   sK   ø€ Ü  ¨Õ!5°{ÓC×IÐIÀr×NÑNÈ{Ó[ˆÜBLÈUÔTX×BYÒBYŒvÑ>¡eÓ>Ó>ÐaÐ_aÐar   r[   )r9   rÔ   s   f r   Ú_peersrÖ   Ð   s   ø€ ÷bð bô �F˜BÓÐr   c               ó    € V ^8„  d   QhRRRR/# )r   r9   r   r   z
list[dict]r	   )r
   s   "r   r   r   Ú   s   € ÷ ñ ˜ð  *ñ r   c                ó(   a € V 3R lp\        V. 4      # )zADesktop relay roster (``tools/bot_relay.py``); [] on any failure.c                 ó    <€ ^ RI Hp  V ! S4      # )é    )Úread_remote_roster)Útools.bot_relayrÛ   )rÛ   r9   s    €r   r¡   Ú_remote_roster.<locals>._readÜ   s   ø€ Ý6á! $Ó'Ð'r   r[   )r9   r¡   s   f r   Ú_remote_rosterrÞ   Ú   s   ø€ õ(ô
 �E˜2ÓÐr   c               ó    € V ^8„  d   QhRRRR/# )r   r9   r   r   r®   r	   )r
   s   "r   r   r   ä   s   € ÷ Vñ V˜Dð V Xñ Vr   c                ó�   € \        V 4       UUu0 uF  w  r\        V4      kK  	  upp\        \        V 4      4      ,          # u uppi )z¼Bare forms this gateway's own profiles answer to (handles + friendly-name slugs); a remote
row must not be offered under any of them, since local resolution wins (``_resolve_local_name``).)rF   r7   rÀ   rÈ   )r9   r.   Ú_ds   &  r   Úlocal_taken_formsrâ   ä   s5   € ô +2°$¬-Ô8©-™h˜dŒG�DŽM©-Ò8¼3¼ÈtÓ?TÓ;UÕUÐUùÓ8s   �Ac               ó    € V ^8„  d   QhRRRR/# ©r   r9   r   r   r   r	   )r
   s   "r   r   r   ê   s   € ÷ ñ ˜Dð  Sñ r   c                ó@  € \        V 4      pV'       g   R# ^ RIHp \        W! V\	        V 4      4      4       UUu. uF?  w  r4\        RV 2RVR,          ;'       g
    VR,           2VR,          VR,          4      NKA  	  pppR	R
P                  V4      ,           # u uppi )zYAddendum for agents on OTHER connected machines; only when the relay roster is non-empty.r�   )Úremote_target_formsÚ@zon Úconnection_labelÚconnection_idrŽ   r‘   uð   

Teammates on OTHER connected machines (reachable through the Desktop relay â€” message them with message_agent exactly like local teammates; replies arrive as completion notifications the same way, or via reply_delivery="poll" as below):
r   )rÞ   rÜ   ræ   Úziprâ   rˆ   r‚   )r9   Úrosterræ   ÚrowrÅ   Úliness   &     r   Ú_remote_paragraphrî   ê   s­   € ä˜DÓ!€FßÙÝ3ô ˜VÐ%8¸ÔARÐSWÓAXÓ%YÔZôáZ‰IˆCô 	�!�D�6�
˜c #Ð&8Õ"9×"QÐ"Q¸SÀÕ=QÐ!RÐSÐUXÐY`ÕUaÐcfÐgtÕcuÖvÙZð 
ñ ð
	;ð >B¿Y¹YÀuÓ=Mõ	Nðùó	s   º BÁ$Bc               ó    € V ^8„  d   QhRRRR/# rä   r	   )r
   s   "r   r   r   ý   s   € ÷ ñ ˜$ð  3ñ r   c                óh   € \        V 4      pV'       g   R# RP                  R V 4       4      pRV R2# )u9   Addendum for cross-machine DMs â€” only when peers exist.r�   z, c              3  ó.   "  € T F  pR V R 2x € K  	  R# 5i)r‡   Nr	   r~   s   & r   rq   Ú"_peer_paragraph.<locals>.<genexpr>  s   é € Ð/© A˜˜1˜#˜Q•x«ùs   ‚zO

Teammates on OTHER machines: this install also has peer gateways registered (u¼   ). Message an agent on a peer the same way â€” message_agent with target "<peer>/<agent-name>" (or "<peer>" alone for the peer's main agent). Run `hermes peer list` for the live peer list.)rÖ   r‚   )r9   rÓ   Úlisteds   &  r   Ú_peer_paragraphrô   ý   s>   € ä�4‹L€EßÙØ�Y‰YÑ/©Ó/Ó/€Fð	Ø�hð ð	ðr   c               ó    € V ^8„  d   QhRRRR/# r1   r	   )r
   s   "r   r   r     s   € ÷ %ñ %˜ð % #ñ %r   c           
     óŽ  € \        V 4      p\        V 4      p\        V4      '       g   R # \        V4       UUu. uF.  w  r4W28w  g   K  \	        R\        V4       2\        V4      4      NK0  	  pppRP                  V4      ;'       g    Rp\         R\        V4       RV 2\        V 4      ,           \        V4      ,           # u uppi )r�   rç   r   z- (no teammates yet)uq  
This install runs Bot Mode: each Hermes profile is an agent teammate with one canonical "Bot Chat" conversation, and you have the `message_agent` tool to DM any of them. It is FIRE-AND-FORGET: it delivers your message with your attribution prefixed automatically and returns an acknowledgement immediately â€” it never returns the reply. Send it, finish your turn, and the reply arrives later as a background-process completion notification that wakes you; relay it to the user then, attributed to that agent â€” unless the ack returns reply_delivery="poll", in which case follow its process(action="wait") instruction before ending the turn. COMPOSE every message yourself â€” say what YOU need from that agent; never forward the user's words verbatim, and never reveal private 1:1 chat content. When the user says "ask <name>" or "tell <name> ...", that is a handoff: pick the right teammate from the roster below, message them with message_agent, and report back naming which agent replied. Message ONE clearly relevant teammate; don't fan out to several unless the user explicitly asked.
When YOU receive a "Message from ðŸ¤– <name> (@<handle>):" message, a teammate agent is talking to you (not the user): address them, reply concisely via message_agent to their handle, and if it is a pure FYI with nothing to add, staying silent is fine â€” never ping-pong acknowledgements.
You are `@z<`. Your teammates (live roster; roles from their profiles):
)r/   r3   rt   rF   rˆ   r7   rš   r‚   r   rî   rô   )r   r9   Úmer.   rp   Úroster_linesÚroster_blocks   &      r   Ú_build_sectionrú     sÉ   € Ü˜Ó€DÜ	�tÓ	€BÜ˜×ÒÙäRYÐZ^ÔR_ÔnÑR_ÁwÀtÐcgÑcmÔB”G˜a¤¨£˜Ð/´¸qÓ1AÖBÑR_€LÑnØ—9‘9˜\Ó*×DÐDÐ.D€Lô Ð
ð ô, ˜R“[�Mð "àˆ.ð1	ô2 ˜DÓ
!õ3	"ô4 ˜$Ó
õ5	 ðùó os   ¸
CÁ%CÚforce_refreshFc               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   rû   rf   r   r   r	   )r
   s   "r   r   r   4  s$   € ÷ !ñ !Ð(@ð !Ð[_ð !Ðloñ !r   c               óô   a€ \        \        V 4      4      o\        ;_uu_ 4        V'       g   S\        9  d   \	        V3R lR4      \        S&   \        S,          uuRRR4       #   + '       g   i     R# ; i)u
  Cached probe entry point â€” one filesystem pass per (process, home). ``home`` should be
the AGENT'S OWN resolved home (session-db derived), not ambient HERMES_HOME â€” build threads
can lose the ContextVar override and the env var would then name the wrong profile.c                 ó,   <€ \        \        S 4      4      # r!   )rú   r   )Úresolveds   €r   rC   Ú/get_bot_mode_protocol_section.<locals>.<lambda>;  s   ø€ ´ÄÀXÃÔ1Or   r�   N)r   r#   Ú_lockr   r(   )r   rû   rÿ   s   &$@r   Úget_bot_mode_protocol_sectionr  4  sJ   ø€ ô ”= Ó&Ó'€Hß	Žß˜H¬GÔ3Ü (Ô)OÐQSÓ TŒG�HÑÜ�xÕ ÷ 
��‹ús   ¤7A&Á&A7	zCapability epoch: z Capability epoch: ([0-9a-f]{12})c               ó    € V ^8„  d   QhRRRR/# )r   Ú	model_cfgÚobjectr   rU   r	   )r
   s   "r   r   r   J  s   € ÷ ñ °ð ¸4ñ r   c                óÌ  € ^ RI Hp \        V \        4      '       g   / p V P	                  R4      pRp\        V\
        4      '       d   RpM€\        V\        4      '       d   V^ 8”  d   TMRpM^\        V\        4      '       dI   VP                  4       P                  4       '       d%   \        VP                  4       4      pV^ 8”  d   TMRpRV! V P	                  R4      4      RV/# )u�  ``model.*`` overrides whose flip changes a rebuilt prompt, coerced like their consumers.

``supports_vision`` uses image routing's strict bool so YAML ``yes`` and ``true`` share
one epoch. ``context_length`` is the cap ``build_system_prompt_parts`` uses to truncate
context files. Routing keys (provider, default, base_url) are identity lines, not this
surface â€” and no model id is special-cased.
)Ú_coerce_capability_boolÚcontext_lengthNÚsupports_vision)
Úagent.image_routingr  rT   rU   ra   rf   Úintr   r   Úisdigit)r  r  Úraw_ctxÚctxÚparseds   &    r   Ú _model_prompt_capability_surfacer  J  s»   € õ <ä�i¤×&Ò&Øˆ	Ø�m‰mÐ,Ó-€GØ
€Cä�'œ4× Ò Ø‰Ü	�GœS×	!Ò	!Ø  1œ‰g¨$‰Ü	�GœS×	!Ò	! g§m¡m£o×&=Ñ&=×&?Ò&?Ü�W—]‘]“_Ó%ˆØ œ
‰f¨ˆàÑ2°9·=±=ÐARÓ3SÓTØ˜#ðð r   c               ó    € V ^8„  d   QhRRRR/# ©r   r   r   r   r   r	   )r
   s   "r   r   r   f  s   € ÷ Sñ SÐ!9ð SÀSñ Sr   c                ó„  aaaa€ ^ RI o^ RIo\        V 4      o\        S4      p/ o ^ RIHp ^ RIHp ^ RIH	pH
p V! \        S4      4      p V! 4       ;'       g    / pV! V4       \        VP                  R4      \        4      '       d   VP                  R4      M/ p\        VP                  R4      \        4      '       d   VP                  R4      M/ p	\        V	4      SR&   \!        R VP                  R	4      ;'       g    .  4       4      SR
&   \        VP                  R4      \        4      '       d   VP                  R4      M/ p
SP#                  VP                  R4      ;'       g    / R\        R7      SR&   \!        V! V
P                  R4      4      4      SR&   VP                  R4      p\        V\        4      '       d   SP#                  VR\        R7      MRSR&   R VV3R llpR V3R llp\'        VR4      SR&   \'        V. 4      SR&    \)        V4      p\!        R V 4       4      SR&   \!        R V 4       4      SR&   ^SR&   \+        V4      SR&   \!        R \-        S4       4       4      SR&   \'        VVV3R  lR!4      #   T! T4       i ; i  \$         d     LÄi ; i  \$         d	    . SR&    Lsi ; i)"u¹  12-hex digest of the capability surface for ``home``'s profile: disabled skills +
enabled toolsets + MCP config, model capability overrides that change the prompt
(``supports_vision``, ``context_length``), SOUL.md bytes, installed skill names, the
Bot-Mode roster (+ roles), peers and the relay roster. Deliberately NOT cached â€” the
point is detecting on-disk drift against a stored prompt's epoch. Never raises
("unavailable" on failure).N)Úparse_config_string_list)Úload_config_readonly)Úreset_hermes_home_overrideÚset_hermes_home_overrideÚskillsÚmodelÚmodel_capabilitiesc              3  óT   "  € T F  p\        V4      P                  4       x € K   	  R # 5ir!   )r   r”   )rn   Úss   & r   rq   Ú)capability_fingerprint.<locals>.<genexpr>‚  s   é € Ð+gÑEe¸q¬C°«F¯L©L¯N¨NÓEeùs   ‚&(ÚdisabledÚdisabled_skillsÚagentÚplatform_toolsetsT)Ú	sort_keysr'   Údisabled_toolsetsÚmcp_serversr�   Úmcpc               ó   € V ^8„  d   QhRR/# r   r	   )r
   s   "r   r   Ú,capability_fingerprint.<locals>.__annotate__�  s   € ÷ Wñ W�3ñ Wr   c                 ó    <€ SR ,          p V P                  4       '       d.   SP                  V P                  4       4      P                  4       # R# )zSOUL.mdr�   )rP   Úsha256Ú
read_bytesÚ	hexdigest)ÚsoulÚhashlibrÿ   s    €€r   Ú_soulÚ%capability_fingerprint.<locals>._soul�  s<   ø€ Ø˜)Õ#ˆØ@DÇÁÇÂˆw�~‰~˜dŸo™oÓ/Ó0×:Ñ:Ó<ÐVÐTVÐVr   c               ó   € V ^8„  d   QhRR/# rÍ   r	   )r
   s   "r   r   r'  “  s   € ÷ Pñ P�Yñ Pr   c                 óŒ   <a€ SR ,          oSP                  4       '       g   . # ^ RIHp  \        V3R lV ! SR4       4       4      # )r  )Úiter_skill_index_filesc              3  ól   <"  € T F)  p\        VP                  P                  S4      4      x € K+  	  R # 5ir!   )r   r-   Úrelative_to)rn   r   Úskills_roots   & €r   rq   Ú:capability_fingerprint.<locals>._skills.<locals>.<genexpr>   s0   øé € ð PÙN˜!ô ˜!Ÿ(™(×.Ñ.¨{Ó;×<Ð<ÛNùs   ƒ14zSKILL.md)r>   Úagent.skill_utilsr2  r?   )r2  r5  rÿ   s    @€r   Ú_skillsÚ'capability_fingerprint.<locals>._skills“  sK   ù€ Ø Õ)ˆØ×!Ñ!×#Ò#ØˆIõ 	=äô PÙ5°kÀ:ÔNóPó Pð 	Pr   r,  c              3  óP   "  € T F  w  r\        V4      '       g   K  Vx € K  	  R # 5ir!   rm   ©rn   r¨   rp   s   &  r   rq   r  §  s   é € Ð"N±©¨¼?È1×;M§1¢1³ùs   ‚&œ
&rë   c              3  óF   "  € T F  w  rV R \        V4       2x € K  	  R# 5i)Ú:N)rš   r;  s   &  r   rq   r  ª  s#   é € Ð(VÉvÁtÀq¨A¨3¨a´¸aÓ0@Ð/AÕ)BËvùs   ‚!Úroster_rolesÚprotocol_versionrÓ   c              3  ó^   "  € T F#  qR ,           RVR,           RVR,           2x € K%  	  R# 5i)ré   r=  ÚprofilerŽ   Nr	   )rn   Úrs   & r   rq   r  ³  s1   é € ð &ÙE]Àˆ_ÕÐ
˜a  )¥˜~¨Q¨q°­z¨lÕ;ÓE]ùs   ‚+-Úremote_rosterc                 ó�   <€ S P                  SP                  SR R7      P                  R4      4      P                  4       R,          # )T)r"  zutf-8:Né   N)r)  ÚdumpsÚencoder+  )r-  ÚjsonÚsurfaces   €€€r   rC   Ú(capability_fingerprint.<locals>.<lambda>·  s5   ø€ �—‘˜tŸz™z¨'¸T˜zÓB×IÑIÈ'ÓRÓS×]Ñ]Ó_Ð`cÖdr   Úunavailable)r-  rH  r#   r/   r7  r  Úhermes_cli.configr  r   r  r  r   rT   ra   rU   r  r?   rF  r%   r(   rF   rÖ   rÞ   )r   r9   r  r  r  r  ÚtokenÚcfgÚ
skills_cfgr  Ú	agent_cfgr%  r.  r8  rë   r-  rH  rÿ   rI  s   &              @@@@r   Úcapability_fingerprintrQ  f  s˜  û€ ó Ûä˜TÓ"€HÜ˜Ó!€DØ€Gðõ 	?Ý:ßYá(¬¨X«Ó7ˆð	.Ù&Ó(×.Ð.¨BˆCá& uÔ-Ü*4°S·W±W¸XÓ5FÌ×*MÒ*M�S—W‘W˜XÔ&ÐSUˆ
Ü(2°3·7±7¸7Ó3CÄT×(JÒ(J�C—G‘G˜GÔ$ÐPRˆ	Ü(HÈÓ(SˆÐ$Ñ%Ü%+Ñ+gÀZÇ^Á^ÐT^ÓE_×EeÐEeÐceÐEeÓ+gÓ%gˆÐ!Ñ"ô
 )3°3·7±7¸7Ó3CÄT×(JÒ(J�C—G‘G˜GÔ$ÐPRˆ	Ø'+§z¡z°#·'±'Ð:MÓ2N×2TÐ2TÐRTÐ`dÔnq zÓ'rˆÐ#Ñ$Ü'-Ñ.FÀyÇ}Á}ÐUhÓGiÓ.jÓ'kˆÐ#Ñ$Ø�g‰g�mÓ$ˆÜISÐTWÔY]×I^ÒI^˜Ÿ™ C°4Ä˜ÔEÐdfˆ�‰÷Wñ W÷Pð Pô  ˜u bÓ)€GˆF�OÜ  ¨"Ó-€GˆHÑðÜ˜“ˆÜ"Ñ"N±Ó"NÓNˆ�Ñô #)Ñ(VÉvÓ(VÓ"Vˆ�Ñð
 #$€GÐÑô ˜d“|€GˆGÑÜ%ñ &ÜESÐT\ÔE]ó&ó  €GˆOÑô ÞdØóð øñq ' uÕ-ûô ô Ùðûô> ô Øˆ�ÓðúsP   ¦%J ÁJ ÁJ ÁB$J ÄA)J Å,A8J È5J, Ê
JÊJ ÊJ)Ê(J)Ê,J?Ê>J?c               ó    € V ^8„  d   QhRRRR/# r  r	   )r
   s   "r   r   r   ¼  s   € ÷ <ñ <Ð-ð <¸ñ <r   c                ó(   € \          \        V 4       2# )z.The epoch stamp appended to a Bot Chat prompt.)Ú_EPOCH_PREFIXrQ  r"   s   &r   Ú
epoch_linerU  ¼  s   € äˆ_Ô3°DÓ9Ð:Ð;Ð;r   c               ó$   € V ^8„  d   QhRRRRRR/# ©r   Ústored_promptr   r   r   r   rf   r	   )r
   s   "r   r   r   Á  s#   € ÷ 
>ñ 
>°#ð 
>Ð=Uð 
>Ðaeñ 
>r   c                óÄ   a€ ^ RI pVP                  ! \        T ;'       g    R4      pV'       g   R# \        V3R lR4      pVR8g  ;'       d    VP	                  ^4      V8g  # )uâ   True when ``stored_prompt`` is a Bot Chat prompt whose embedded epoch no
longer matches disk. Unstamped prompts are never stale. Fails closed to
"not stale" â€” a broken probe must not become a rebuild-every-turn cache burner.Nr�   Fc                 ó   <€ \        S 4      # r!   )rQ  r"   s   €r   rC   Ú0stored_prompt_capability_stale.<locals>.<lambda>Ê  s   ø€ Ô5°dÔ;r   rK  )r±   ÚsearchÚ_EPOCH_RE_TEXTr(   Úgroup)rX  r   r±   ÚmÚcurrents   &f   r   Ústored_prompt_capability_stalera  Á  sS   ø€ ó à
�	Š	”. -×"5Ð"5°2Ó6€AßÙÜÔ;¸]ÓK€GØ�mÑ#×=Ð=¨¯©°«
°gÑ(=Ð=r   c               ó$   € V ^8„  d   QhRRRRRR/# rW  r	   )r
   s   "r   r   r   Î  s(   € ÷ Nñ N¸ð NÐC[ð NÐgkñ Nr   c                óR   a€ \         T ;'       g    R9   d   R# \        V3R lR4      # )uZ  True when a Bot Chat session's stored prompt PREDATES the epoch mechanism (no stamp â€”
including SOUL-era prompts whose frozen roster rode in from SOUL.md). The caller must only
ask for sessions titled "Bot Chat"; we rebuild only when the probe would actually emit a
section, and every rebuilt prompt is stamped so this fires once. Fails closed.r�   Fc                 ó,   <€ \        \        S 4      4      # r!   )rf   r  r"   s   €r   rC   Ú6stored_bot_chat_prompt_needs_upgrade.<locals>.<lambda>Õ  s   ø€ œDÔ!>¸tÓ!DÔEr   )rT  r(   )rX  r   s   &fr   Ú$stored_bot_chat_prompt_needs_upgraderf  Î  s&   ø€ ô
 ˜×,Ð,¨"Ô-ÙÜÔEÀuÓMÐMr   c               ó   € V ^8„  d   QhRR/# )r   r   ÚNoner	   )r
   s   "r   r   r   Ø  s   € ÷ ñ  ñ r   c                 ó„   € \         ;_uu_ 4        \        P                  4        R R R 4       R #   + '       g   i     R # ; ir!   )r  r   Úclearr	   r   r   Ú_reset_cache_for_testsrk  Ø  s   € ß	ŽÜ�‰Œ÷ 
��Šús   �.®?	r!   >   ÚallÚuserr6   r'   Úeveryone)8Ú__conditional_annotations__Ú__doc__Ú
__future__r   Úosr±   Ú	threadingÚpathlibr   r   ÚcompileÚescapeÚDOTALLr   r   ÚBOT_CHAT_TITLEÚLockr  r   Ú__annotations__r   r#   r(   r/   r3   r7   rF   r\   rc   ri   rt   ry   rƒ   rˆ   rš   r£   r«   Ú	frozensetr³   r·   rÈ   rÖ   rÞ   râ   rî   rô   rú   r  rT  r]  r  rQ  rU  ra  rf  rk  )ro  s   @r   Ú<module>r|     sD  øðô
õ #ã 	Û 	Û Ý à/Ð à—j’j ¨"¯)ª)Ð4EÓ*FÕ!FÐIcÕ!cÐeg×enÑenÓoÐ õeð €à�ŠÓ€Ø€ˆÓ õ*õ8òõJõ
Fõ3õ
'÷*!õ"4õ`õ>÷Tõ/õ
/õ
õ$%õWñ ÒNÓOÐ õ]õ õ  õõVõõ&õ%ñP!Ðbg÷ !ð !ð$ %€Ø4€õ÷8S÷l<÷

>÷N÷r   