2727from gnomon .config import parse_ts , line_count , strip_injections
2828from gnomon .taxonomy import (
2929 SCHEDULE_TOOLS , ASK_TOOLS , PLAN_SIGNAL_TOOLS , PLAN_SKILL_NEEDLES ,
30+ KNOWLEDGE_SKILL_NEEDLES ,
3031 classify_tool , classify_mcp_subcategory , CI_CONTEXT_SUBCATS ,
31- bash_writes_file , bash_runs_tests , _extract_clis ,
32+ bash_writes_file , bash_runs_tests , bash_runs_knowledge , _extract_clis ,
3233 _is_compounding_path , _SKILL_MD_RX ,
3334)
3435from gnomon .sources .discovery import _AGENT_UNSUPPORTED_SOURCES
4748BURST_GAP_S = 1800 # a gap > 30 min ends a contiguous work "run"
4849DOW = ["Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" , "Sun" ]
4950
51+ _KNOWLEDGE_NATIVE_TOOLS = frozenset ({"WebFetch" , "WebSearch" })
52+
53+
54+ def _is_local_url (url ):
55+ if not url :
56+ return False
57+ low = url .lower ()
58+ return any (h in low for h in ("localhost" , "127.0.0.1" , "0.0.0.0" , "[::1]" ))
59+
5060
5161def _zero_tok ():
5262 return {"input" : 0 , "output" : 0 , "cache_read" : 0 , "cache_creation" : 0 }
@@ -218,6 +228,10 @@ def _is_plan_skill(name):
218228 sl = str (name ).lower ()
219229 return any (nd in sl for nd in PLAN_SKILL_NEEDLES )
220230
231+ def _is_knowledge_skill (self , name ):
232+ low = (name or "" ).lower ()
233+ return any (n in low for n in KNOWLEDGE_SKILL_NEEDLES )
234+
221235 def _mark_plan_session (self , sid , mkey ):
222236 """Record that session `sid` (in month `mkey`) contained a planning signal.
223237 Idempotent per session — repeated signals in one session count once."""
@@ -433,6 +447,8 @@ def observe(self, ev, since_dt, until_dt):
433447 self .month_skill_counter [mkey ][ev ["attributionSkill" ]] += 1
434448 if self ._is_plan_skill (ev ["attributionSkill" ]):
435449 self ._mark_plan_session (sid , mkey )
450+ if self ._is_knowledge_skill (ev ["attributionSkill" ]):
451+ self ._pending_knowledge_grounding [sid ] = True
436452 content = msg .get ("content" )
437453 if isinstance (content , list ):
438454 for b in content :
@@ -484,6 +500,11 @@ def observe(self, ev, since_dt, until_dt):
484500 else :
485501 self .native_calls += 1
486502
503+ if sid and name in _KNOWLEDGE_NATIVE_TOOLS :
504+ url = inp .get ("url" , "" )
505+ if not _is_local_url (url ):
506+ self ._pending_knowledge_grounding [sid ] = True
507+
487508 # a tool use after a pending error = recovery
488509 if sid and self ._pending_error .get (sid ):
489510 self .recovered_errors += 1
@@ -500,6 +521,8 @@ def observe(self, ev, since_dt, until_dt):
500521 # a planning Skill also marks this a planning session
501522 if self ._is_plan_skill (s ):
502523 self ._mark_plan_session (sid , mkey )
524+ if self ._is_knowledge_skill (s ):
525+ self ._pending_knowledge_grounding [sid ] = True
503526 # Plan-ceremony signal: mark this SESSION as a planning session.
504527 # PLAN_SIGNAL_TOOLS normalizes across sources (EnterPlanMode = Cursor
505528 # create_plan; ExitPlanMode = Claude Code native plan mode, shift+tab ->
@@ -512,10 +535,10 @@ def observe(self, ev, since_dt, until_dt):
512535 if name == "Agent" :
513536 st = inp .get ("subagent_type" , "general-purpose" )
514537 self .subagent_counter [st ] += 1
515- # A planning subagent (SDD planning phases, the built-in Plan
516- # agent, *-planner types) also marks this a planning session.
517538 if self ._is_plan_skill (st ):
518539 self ._mark_plan_session (sid , mkey )
540+ if self ._is_knowledge_skill (st ):
541+ self ._pending_knowledge_grounding [sid ] = True
519542 if mkey :
520543 self .month_subagent_counter [mkey ][st ] += 1
521544 if sid :
@@ -623,6 +646,8 @@ def observe(self, ev, since_dt, until_dt):
623646 self .month_skill_counter [mkey ][_sm .group (1 )] += 1
624647 if self ._is_plan_skill (_sm .group (1 )):
625648 self ._mark_plan_session (sid , mkey )
649+ if self ._is_knowledge_skill (_sm .group (1 )):
650+ self ._pending_knowledge_grounding [sid ] = True
626651 if bash_writes_file (cmd ):
627652 self .bash_write_calls += 1
628653 _bash_nl = cmd .count ("\n " )
@@ -634,6 +659,8 @@ def observe(self, ev, since_dt, until_dt):
634659 self .shell_test_runs += 1
635660 if mkey :
636661 self .month_shell_test_runs [mkey ] += 1
662+ if bash_runs_knowledge (cmd ):
663+ self ._pending_knowledge_grounding [sid ] = True
637664 if "git commit" in cmd :
638665 self .git_commits += 1
639666 # flush iteration-depth run for this session
0 commit comments