arkaos 4.22.0 → 4.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/README.md +1 -1
  2. package/THE-ARKAOS-GUIDE.md +72 -0
  3. package/VERSION +1 -1
  4. package/arka/SKILL.md +29 -7
  5. package/arka/skills/bootstrap-agent/SKILL.md +3 -2
  6. package/arka/skills/conclave/SKILL.md +11 -0
  7. package/arka/skills/flow/SKILL.md +3 -2
  8. package/arka/skills/forge/SKILL.md +3 -2
  9. package/arka/skills/recipes/SKILL.md +3 -2
  10. package/arka/skills/refine/SKILL.md +3 -2
  11. package/arka/skills/research/SKILL.md +3 -2
  12. package/bin/arka-doctor +8 -0
  13. package/core/cognition/insights/store.py +15 -4
  14. package/core/forge/persistence.py +27 -9
  15. package/core/forge/schema.py +45 -22
  16. package/core/governance/evidence_checks.py +101 -9
  17. package/core/governance/kb_cite_check.py +16 -6
  18. package/core/governance/stop_lint.py +38 -11
  19. package/core/governance/stop_lint_telemetry.py +11 -2
  20. package/core/hooks/user_prompt_submit.py +21 -23
  21. package/core/synapse/engine.py +46 -16
  22. package/core/synapse/graph_context_layer.py +7 -2
  23. package/core/synapse/kb_cache.py +63 -16
  24. package/core/synapse/layers.py +93 -30
  25. package/core/synapse/layers_base.py +16 -0
  26. package/core/synapse/layers_kb.py +325 -19
  27. package/dashboard/app/layouts/default.vue +7 -0
  28. package/dashboard/app/pages/plan-canvas.vue +630 -0
  29. package/departments/brand/SKILL.md +3 -2
  30. package/departments/brand/skills/archetype-finder/SKILL.md +3 -2
  31. package/departments/brand/skills/colors/SKILL.md +3 -2
  32. package/departments/brand/skills/design-system/SKILL.md +3 -2
  33. package/departments/brand/skills/identity-system/SKILL.md +3 -2
  34. package/departments/brand/skills/logo-brief/SKILL.md +3 -2
  35. package/departments/brand/skills/mockup-generate/SKILL.md +3 -2
  36. package/departments/brand/skills/naming-evaluate/SKILL.md +3 -2
  37. package/departments/brand/skills/positioning-statement/SKILL.md +3 -2
  38. package/departments/brand/skills/primal-audit/SKILL.md +3 -2
  39. package/departments/brand/skills/ux-audit/SKILL.md +3 -2
  40. package/departments/brand/skills/voice-guide/SKILL.md +3 -2
  41. package/departments/brand/skills/wireframe/SKILL.md +3 -2
  42. package/departments/community/SKILL.md +3 -2
  43. package/departments/community/skills/ai-community/SKILL.md +3 -2
  44. package/departments/community/skills/betting-setup/SKILL.md +3 -2
  45. package/departments/community/skills/business-model/SKILL.md +3 -2
  46. package/departments/community/skills/content-calendar/SKILL.md +3 -2
  47. package/departments/community/skills/events-plan/SKILL.md +3 -2
  48. package/departments/community/skills/gamification-design/SKILL.md +3 -2
  49. package/departments/community/skills/growth-plan/SKILL.md +3 -2
  50. package/departments/community/skills/metrics-track/SKILL.md +3 -2
  51. package/departments/community/skills/moderation/SKILL.md +3 -2
  52. package/departments/community/skills/monetize-plan/SKILL.md +3 -2
  53. package/departments/community/skills/niche-setup/SKILL.md +3 -2
  54. package/departments/community/skills/onboarding-flow/SKILL.md +3 -2
  55. package/departments/community/skills/platform-select/SKILL.md +3 -2
  56. package/departments/content/SKILL.md +3 -2
  57. package/departments/content/skills/ai-workflow/SKILL.md +3 -2
  58. package/departments/content/skills/analytics/SKILL.md +3 -2
  59. package/departments/content/skills/calendar/SKILL.md +3 -2
  60. package/departments/content/skills/content-system/SKILL.md +3 -2
  61. package/departments/content/skills/monetization-plan/SKILL.md +3 -2
  62. package/departments/content/skills/newsletter-write/SKILL.md +3 -2
  63. package/departments/content/skills/platform-optimize/SKILL.md +3 -2
  64. package/departments/content/skills/repurpose-plan/SKILL.md +3 -2
  65. package/departments/content/skills/research-compile/SKILL.md +3 -2
  66. package/departments/content/skills/script-structure/SKILL.md +3 -2
  67. package/departments/content/skills/short-form/SKILL.md +3 -2
  68. package/departments/content/skills/thumbnail-package/SKILL.md +3 -2
  69. package/departments/content/skills/trend-hunt/SKILL.md +3 -2
  70. package/departments/content/skills/video-produce/SKILL.md +3 -2
  71. package/departments/content/skills/video-setup/SKILL.md +3 -2
  72. package/departments/content/skills/viral-design/SKILL.md +3 -2
  73. package/departments/content/skills/youtube-strategy/SKILL.md +3 -2
  74. package/departments/dev/SKILL.md +3 -2
  75. package/departments/dev/skills/ai-assisted-dev/SKILL.md +3 -2
  76. package/departments/dev/skills/animated-website/SKILL.md +7 -0
  77. package/departments/dev/skills/architecture-design/SKILL.md +3 -2
  78. package/departments/dev/skills/code-review/SKILL.md +3 -2
  79. package/departments/dev/skills/db-design/SKILL.md +3 -2
  80. package/departments/dev/skills/ddd-model/SKILL.md +3 -2
  81. package/departments/dev/skills/demo-gif/SKILL.md +3 -2
  82. package/departments/dev/skills/deploy/SKILL.md +3 -2
  83. package/departments/dev/skills/devops-pipeline/SKILL.md +3 -2
  84. package/departments/dev/skills/docs/SKILL.md +3 -2
  85. package/departments/dev/skills/evaluator-build-loop/SKILL.md +93 -0
  86. package/departments/dev/skills/mcp/SKILL.md +3 -2
  87. package/departments/dev/skills/performance-audit/SKILL.md +3 -2
  88. package/departments/dev/skills/refactor-plan/SKILL.md +3 -2
  89. package/departments/dev/skills/research/SKILL.md +3 -2
  90. package/departments/dev/skills/security-compliance/SKILL.md +3 -2
  91. package/departments/dev/skills/spec-miner/SKILL.md +86 -0
  92. package/departments/dev/skills/stack-check/SKILL.md +3 -2
  93. package/departments/ecom/SKILL.md +3 -2
  94. package/departments/ecom/skills/analytics/SKILL.md +3 -2
  95. package/departments/ecom/skills/browse-competitor/SKILL.md +3 -2
  96. package/departments/ecom/skills/cart-recovery/SKILL.md +3 -2
  97. package/departments/ecom/skills/cro-optimize/SKILL.md +3 -2
  98. package/departments/ecom/skills/customer-journey/SKILL.md +3 -2
  99. package/departments/ecom/skills/fulfillment-plan/SKILL.md +3 -2
  100. package/departments/ecom/skills/marketplace-manage/SKILL.md +3 -2
  101. package/departments/ecom/skills/pricing-strategy/SKILL.md +3 -2
  102. package/departments/ecom/skills/product-launch/SKILL.md +3 -2
  103. package/departments/ecom/skills/rfm-segment/SKILL.md +3 -2
  104. package/departments/ecom/skills/social-commerce/SKILL.md +3 -2
  105. package/departments/ecom/skills/store-audit/SKILL.md +3 -2
  106. package/departments/ecom/skills/subscription-model/SKILL.md +3 -2
  107. package/departments/finance/SKILL.md +3 -2
  108. package/departments/finance/skills/budget-plan/SKILL.md +3 -2
  109. package/departments/finance/skills/cashflow-forecast/SKILL.md +3 -2
  110. package/departments/finance/skills/ciso-advisor/SKILL.md +3 -2
  111. package/departments/finance/skills/financial-model/SKILL.md +3 -2
  112. package/departments/finance/skills/pitch-deck/SKILL.md +3 -2
  113. package/departments/finance/skills/scenario-analysis/SKILL.md +3 -2
  114. package/departments/finance/skills/unit-economics/SKILL.md +3 -2
  115. package/departments/finance/skills/valuation-model/SKILL.md +3 -2
  116. package/departments/kb/SKILL.md +3 -2
  117. package/departments/kb/skills/ai-research/SKILL.md +3 -2
  118. package/departments/kb/skills/competitive-intel/SKILL.md +3 -2
  119. package/departments/kb/skills/doc-extraction/SKILL.md +3 -2
  120. package/departments/kb/skills/doc-redaction/SKILL.md +3 -2
  121. package/departments/kb/skills/knowledge-ops/SKILL.md +3 -2
  122. package/departments/kb/skills/knowledge-review/SKILL.md +3 -2
  123. package/departments/kb/skills/learn-content/SKILL.md +3 -2
  124. package/departments/kb/skills/moc-create/SKILL.md +3 -2
  125. package/departments/kb/skills/persona-build/SKILL.md +3 -2
  126. package/departments/kb/skills/research-plan/SKILL.md +3 -2
  127. package/departments/kb/skills/search-kb/SKILL.md +3 -2
  128. package/departments/kb/skills/source-evaluate/SKILL.md +3 -2
  129. package/departments/kb/skills/taxonomy-manage/SKILL.md +3 -2
  130. package/departments/kb/skills/write-as-persona/SKILL.md +3 -2
  131. package/departments/landing/SKILL.md +3 -2
  132. package/departments/landing/skills/ab-test/SKILL.md +3 -2
  133. package/departments/landing/skills/affiliate-bridge/SKILL.md +3 -2
  134. package/departments/landing/skills/awareness-diagnose/SKILL.md +3 -2
  135. package/departments/landing/skills/email-sequence/SKILL.md +3 -2
  136. package/departments/landing/skills/funnel-metrics/SKILL.md +3 -2
  137. package/departments/landing/skills/headline-write/SKILL.md +3 -2
  138. package/departments/landing/skills/launch-sequence/SKILL.md +3 -2
  139. package/departments/landing/skills/offer-create/SKILL.md +3 -2
  140. package/departments/landing/skills/optimize-page/SKILL.md +3 -2
  141. package/departments/landing/skills/page-architect/SKILL.md +3 -2
  142. package/departments/landing/skills/persuasion-apply/SKILL.md +3 -2
  143. package/departments/landing/skills/webinar-funnel/SKILL.md +3 -2
  144. package/departments/leadership/SKILL.md +3 -2
  145. package/departments/leadership/skills/change-manage/SKILL.md +3 -2
  146. package/departments/leadership/skills/conflict-resolve/SKILL.md +3 -2
  147. package/departments/leadership/skills/culture-audit/SKILL.md +3 -2
  148. package/departments/leadership/skills/delegation-matrix/SKILL.md +3 -2
  149. package/departments/leadership/skills/disc-assess/SKILL.md +3 -2
  150. package/departments/leadership/skills/feedback-give/SKILL.md +3 -2
  151. package/departments/leadership/skills/hiring-plan/SKILL.md +3 -2
  152. package/departments/leadership/skills/performance-review/SKILL.md +3 -2
  153. package/departments/marketing/SKILL.md +3 -2
  154. package/departments/marketing/skills/ab-test/SKILL.md +3 -2
  155. package/departments/marketing/skills/analytics-report/SKILL.md +3 -2
  156. package/departments/marketing/skills/audience-segment/SKILL.md +3 -2
  157. package/departments/marketing/skills/calendar-plan/SKILL.md +3 -2
  158. package/departments/marketing/skills/competitor-analysis/SKILL.md +3 -2
  159. package/departments/marketing/skills/content-audit/SKILL.md +3 -2
  160. package/departments/marketing/skills/email-sequence/SKILL.md +3 -2
  161. package/departments/marketing/skills/growth-loop/SKILL.md +3 -2
  162. package/departments/marketing/skills/marketing-automation/SKILL.md +3 -2
  163. package/departments/marketing/skills/paid-campaign/SKILL.md +3 -2
  164. package/departments/marketing/skills/programmatic-seo/SKILL.md +3 -2
  165. package/departments/marketing/skills/seo-audit/SKILL.md +3 -2
  166. package/departments/marketing/skills/social-strategy/SKILL.md +3 -2
  167. package/departments/ops/SKILL.md +3 -2
  168. package/departments/ops/skills/bottleneck-find/SKILL.md +3 -2
  169. package/departments/ops/skills/dashboard-build/SKILL.md +3 -2
  170. package/departments/ops/skills/gdpr-compliance/SKILL.md +3 -2
  171. package/departments/ops/skills/github-ops/SKILL.md +3 -2
  172. package/departments/ops/skills/gtd-setup/SKILL.md +3 -2
  173. package/departments/ops/skills/integration-design/SKILL.md +3 -2
  174. package/departments/ops/skills/iso27001/SKILL.md +3 -2
  175. package/departments/ops/skills/lean-audit/SKILL.md +3 -2
  176. package/departments/ops/skills/metrics-dashboard/SKILL.md +3 -2
  177. package/departments/ops/skills/n8n-flow/SKILL.md +3 -2
  178. package/departments/ops/skills/quality-management/SKILL.md +3 -2
  179. package/departments/ops/skills/risk-management/SKILL.md +3 -2
  180. package/departments/ops/skills/soc2-compliance/SKILL.md +3 -2
  181. package/departments/ops/skills/sop-create/SKILL.md +3 -2
  182. package/departments/ops/skills/terminal-ops/SKILL.md +3 -2
  183. package/departments/ops/skills/workflow-automate/SKILL.md +3 -2
  184. package/departments/ops/skills/zapier-flow/SKILL.md +3 -2
  185. package/departments/org/SKILL.md +3 -2
  186. package/departments/org/skills/compensation-plan/SKILL.md +3 -2
  187. package/departments/org/skills/culture-define/SKILL.md +3 -2
  188. package/departments/org/skills/decision-framework/SKILL.md +3 -2
  189. package/departments/org/skills/hiring-plan/SKILL.md +3 -2
  190. package/departments/org/skills/meeting-optimize/SKILL.md +3 -2
  191. package/departments/org/skills/onboarding-design/SKILL.md +3 -2
  192. package/departments/org/skills/org-design/SKILL.md +3 -2
  193. package/departments/org/skills/remote-setup/SKILL.md +3 -2
  194. package/departments/org/skills/sop-process/SKILL.md +3 -2
  195. package/departments/org/skills/team-assess/SKILL.md +3 -2
  196. package/departments/pm/SKILL.md +3 -2
  197. package/departments/pm/skills/backlog-groom/SKILL.md +3 -2
  198. package/departments/pm/skills/discovery-plan/SKILL.md +3 -2
  199. package/departments/pm/skills/estimate-forecast/SKILL.md +3 -2
  200. package/departments/pm/skills/impact-map/SKILL.md +3 -2
  201. package/departments/pm/skills/kanban-setup/SKILL.md +3 -2
  202. package/departments/pm/skills/risk-register/SKILL.md +3 -2
  203. package/departments/pm/skills/roadmap-build/SKILL.md +3 -2
  204. package/departments/pm/skills/sprint-plan/SKILL.md +3 -2
  205. package/departments/pm/skills/stakeholder-map/SKILL.md +3 -2
  206. package/departments/pm/skills/standup-run/SKILL.md +3 -2
  207. package/departments/pm/skills/story-write/SKILL.md +3 -2
  208. package/departments/saas/SKILL.md +3 -2
  209. package/departments/saas/skills/benchmark-compare/SKILL.md +3 -2
  210. package/departments/saas/skills/churn-analysis/SKILL.md +3 -2
  211. package/departments/saas/skills/customer-success/SKILL.md +3 -2
  212. package/departments/saas/skills/growth-plan/SKILL.md +3 -2
  213. package/departments/saas/skills/gtm-strategy/SKILL.md +3 -2
  214. package/departments/saas/skills/launch-execute/SKILL.md +3 -2
  215. package/departments/saas/skills/metrics-dashboard/SKILL.md +3 -2
  216. package/departments/saas/skills/micro-saas-stack/SKILL.md +3 -2
  217. package/departments/saas/skills/mvp-build/SKILL.md +3 -2
  218. package/departments/saas/skills/niche-evaluate/SKILL.md +3 -2
  219. package/departments/saas/skills/onboarding-optimize/SKILL.md +3 -2
  220. package/departments/saas/skills/plg-setup/SKILL.md +3 -2
  221. package/departments/saas/skills/pricing-strategy/SKILL.md +3 -2
  222. package/departments/saas/skills/validate-idea/SKILL.md +3 -2
  223. package/departments/sales/SKILL.md +3 -2
  224. package/departments/sales/skills/challenger-sell/SKILL.md +3 -2
  225. package/departments/sales/skills/deal-qualify/SKILL.md +3 -2
  226. package/departments/sales/skills/discovery-call/SKILL.md +3 -2
  227. package/departments/sales/skills/forecast-revenue/SKILL.md +3 -2
  228. package/departments/sales/skills/negotiate-plan/SKILL.md +3 -2
  229. package/departments/sales/skills/objection-handle/SKILL.md +3 -2
  230. package/departments/sales/skills/pipeline-manage/SKILL.md +3 -2
  231. package/departments/sales/skills/pricing-negotiate/SKILL.md +3 -2
  232. package/departments/strategy/SKILL.md +3 -2
  233. package/departments/strategy/skills/blue-ocean/SKILL.md +3 -2
  234. package/departments/strategy/skills/bmc/SKILL.md +3 -2
  235. package/departments/strategy/skills/board-advisor/SKILL.md +3 -2
  236. package/departments/strategy/skills/cto-advisor/SKILL.md +3 -2
  237. package/departments/strategy/skills/extract-data/SKILL.md +3 -2
  238. package/departments/strategy/skills/five-forces/SKILL.md +3 -2
  239. package/departments/strategy/skills/growth-strategy/SKILL.md +3 -2
  240. package/departments/strategy/skills/moat-analysis/SKILL.md +3 -2
  241. package/departments/strategy/skills/position/SKILL.md +3 -2
  242. package/departments/strategy/skills/scenario-plan/SKILL.md +3 -2
  243. package/installer/config-seed.js +81 -25
  244. package/installer/graphify.js +340 -0
  245. package/installer/index.js +8 -1
  246. package/installer/keys.js +18 -3
  247. package/installer/update.js +8 -1
  248. package/knowledge/skills-manifest.json +27 -1
  249. package/mcps/registry.json +9 -9
  250. package/mcps/scripts/apply-mcps.sh +6 -2
  251. package/package.json +2 -1
  252. package/pyproject.toml +1 -1
  253. package/scripts/dashboard-api.py +336 -124
  254. package/scripts/guide_gen.py +139 -0
  255. package/scripts/migrate_skills_kb_first.py +3 -2
  256. package/scripts/synapse-bridge.py +9 -1
@@ -20,6 +20,7 @@ Turn-scoped marker (record_obsidian_query / read_obsidian_query):
20
20
  as core.workflow.marker_cache).
21
21
  """
22
22
 
23
+ import contextlib
23
24
  import hashlib
24
25
  import json
25
26
  import os
@@ -27,12 +28,11 @@ import threading
27
28
  import time
28
29
  import uuid
29
30
  from pathlib import Path
30
- from typing import Any, Optional
31
+ from typing import Any
31
32
 
32
33
  from core.shared import safe_session_id as _safe_session_id_module
33
34
  from core.shared.temp_paths import arkaos_temp_dir
34
35
 
35
-
36
36
  # Re-export for backward compatibility with any external importers.
37
37
  SAFE_SESSION_ID_RE = _safe_session_id_module.SAFE_SESSION_ID_RE
38
38
  KB_QUERY_MARKER_DIR = arkaos_temp_dir("arkaos-kb-query")
@@ -147,8 +147,8 @@ class KBSessionCache:
147
147
  def __init__(
148
148
  self,
149
149
  session_id: str,
150
- project_path: Optional[str] = None,
151
- cache_dir: Optional[str] = None,
150
+ project_path: str | None = None,
151
+ cache_dir: str | None = None,
152
152
  max_entries: int = 150,
153
153
  ttl_seconds: int = 5400,
154
154
  ) -> None:
@@ -278,8 +278,8 @@ class KBSessionCache:
278
278
 
279
279
  def retrieve(
280
280
  self,
281
- query: Optional[str] = None,
282
- topics: Optional[set[str]] = None,
281
+ query: str | None = None,
282
+ topics: set[str] | None = None,
283
283
  threshold: float = 0.3,
284
284
  ) -> list[dict]:
285
285
  """Retrieve cached knowledge by query or topic overlap.
@@ -433,11 +433,44 @@ def _kb_query_dir() -> Path:
433
433
  return KB_QUERY_MARKER_DIR
434
434
 
435
435
 
436
- def _kb_query_path(session_id: str) -> Optional[Path]:
436
+ def _kb_query_path(session_id: str, kind: str = "obsidian") -> Path | None:
437
+ """Turn-scoped marker path for one KB source.
438
+
439
+ ``kind`` separates the sources so a graphify consult cannot satisfy a
440
+ check that asked about Obsidian, or vice versa. "obsidian" keeps the
441
+ historical unsuffixed filename so existing records stay readable.
442
+ """
437
443
  safe = _safe_session_id_module.safe_session_id(session_id)
438
444
  if safe is None:
439
445
  return None
440
- return _kb_query_dir() / f"{safe}.json"
446
+ suffix = "" if kind == "obsidian" else f".{kind}"
447
+ return _kb_query_dir() / f"{safe}{suffix}.json"
448
+
449
+
450
+ def record_graphify_query(session_id: str, query: str, hit_count: int = 0) -> None:
451
+ """Record that a Graphify graph query ran in this turn.
452
+
453
+ Counterpart to :func:`record_obsidian_query`. Without it the ``[graph:``
454
+ citation marker is pure narration — anyone can type ``[graph: MadeUpNode]``
455
+ and earn credit (QG review). A consumer that wants evidence rather than a
456
+ claim should require :func:`graphify_queried_this_turn` alongside it.
457
+ """
458
+ _record_query(session_id, query, hit_count, kind="graphify")
459
+
460
+
461
+ def read_graphify_query(session_id: str) -> dict | None:
462
+ """Return the turn-scoped Graphify-query record, or None if absent."""
463
+ return _read_query(session_id, kind="graphify")
464
+
465
+
466
+ def graphify_queried_this_turn(session_id: str) -> bool:
467
+ """True iff ``record_graphify_query`` was called since turn start."""
468
+ return read_graphify_query(session_id) is not None
469
+
470
+
471
+ def invalidate_graphify_query(session_id: str) -> None:
472
+ """Clear the per-turn Graphify consult marker. Idempotent."""
473
+ _invalidate_query(session_id, kind="graphify")
441
474
 
442
475
 
443
476
  def record_obsidian_query(session_id: str, query: str, hit_count: int = 0) -> None:
@@ -455,7 +488,12 @@ def record_obsidian_query(session_id: str, query: str, hit_count: int = 0) -> No
455
488
  query: The query string that was executed.
456
489
  hit_count: Number of notes returned (0 means search ran but empty).
457
490
  """
458
- path = _kb_query_path(session_id)
491
+ _record_query(session_id, query, hit_count, kind="obsidian")
492
+
493
+
494
+ def _record_query(session_id: str, query: str, hit_count: int, kind: str) -> None:
495
+ """Shared writer for every KB source marker. Atomic tmp+rename."""
496
+ path = _kb_query_path(session_id, kind)
459
497
  if path is None:
460
498
  return
461
499
  safe_query = (query or "")[:_MAX_QUERY_LEN]
@@ -464,7 +502,7 @@ def record_obsidian_query(session_id: str, query: str, hit_count: int = 0) -> No
464
502
  except (TypeError, ValueError):
465
503
  hits = 0
466
504
  now = time.time()
467
- existing = read_obsidian_query(session_id) or {}
505
+ existing = _read_query(session_id, kind) or {}
468
506
  queries_raw = existing.get("queries")
469
507
  queries = list(queries_raw) if isinstance(queries_raw, list) else []
470
508
  queries.append({"query": safe_query, "hit_count": hits, "ts": now})
@@ -472,6 +510,7 @@ def record_obsidian_query(session_id: str, query: str, hit_count: int = 0) -> No
472
510
  queries = queries[-_MAX_QUERIES_PER_TURN:]
473
511
  record = {
474
512
  "session_id": session_id,
513
+ "kind": kind,
475
514
  "queries": queries,
476
515
  "last_query_ts": now,
477
516
  "last_hit_count": hits,
@@ -483,15 +522,18 @@ def record_obsidian_query(session_id: str, query: str, hit_count: int = 0) -> No
483
522
  tmp.write_text(json.dumps(record), encoding="utf-8")
484
523
  os.replace(tmp, path)
485
524
  except OSError:
486
- try:
525
+ with contextlib.suppress(FileNotFoundError):
487
526
  tmp.unlink()
488
- except FileNotFoundError:
489
- pass
490
527
 
491
528
 
492
- def read_obsidian_query(session_id: str) -> Optional[dict]:
529
+ def read_obsidian_query(session_id: str) -> dict | None:
493
530
  """Return the turn-scoped Obsidian-query record, or None if absent."""
494
- path = _kb_query_path(session_id)
531
+ return _read_query(session_id, kind="obsidian")
532
+
533
+
534
+ def _read_query(session_id: str, kind: str) -> dict | None:
535
+ """Shared reader for every KB source marker."""
536
+ path = _kb_query_path(session_id, kind)
495
537
  if path is None or not path.exists():
496
538
  return None
497
539
  try:
@@ -510,7 +552,12 @@ def obsidian_queried_this_turn(session_id: str) -> bool:
510
552
 
511
553
  def invalidate_obsidian_query(session_id: str) -> None:
512
554
  """Clear the per-turn KB consult marker. Idempotent."""
513
- path = _kb_query_path(session_id)
555
+ _invalidate_query(session_id, kind="obsidian")
556
+
557
+
558
+ def _invalidate_query(session_id: str, kind: str) -> None:
559
+ """Shared invalidator for every KB source marker."""
560
+ path = _kb_query_path(session_id, kind)
514
561
  if path is None:
515
562
  return
516
563
  try:
@@ -28,20 +28,20 @@ from typing import Any
28
28
  from core.synapse.layers_base import Layer, LayerResult, PromptContext
29
29
 
30
30
  __all__ = [
31
- "Layer",
32
- "LayerResult",
33
- "PromptContext",
34
- "ConstitutionLayer",
35
- "DepartmentLayer",
36
31
  "AgentLayer",
37
- "ProjectLayer",
38
32
  "BranchLayer",
39
33
  "CommandHintsLayer",
40
- "QualityGateLayer",
41
- "KnowledgeRetrievalLayer",
34
+ "ConstitutionLayer",
35
+ "DepartmentLayer",
42
36
  "ForgeContextLayer",
43
- "SessionContextLayer",
44
37
  "KBContextLayer",
38
+ "KnowledgeRetrievalLayer",
39
+ "Layer",
40
+ "LayerResult",
41
+ "ProjectLayer",
42
+ "PromptContext",
43
+ "QualityGateLayer",
44
+ "SessionContextLayer",
45
45
  ]
46
46
 
47
47
 
@@ -90,22 +90,75 @@ class ConstitutionLayer(Layer):
90
90
  # --- L1: Department Detection ---
91
91
 
92
92
  DEPARTMENT_PATTERNS: dict[str, str] = {
93
- "dev": r"\b(build|code|feature|deploy|test|review|scaffold|debug|refactor|api|migration|stack|implement|fix|bug)\b",
94
- "marketing": r"\b(social|content|campaign|post|instagram|linkedin|twitter|tiktok|seo|marketing|ads|email.?campaign|growth|viral)\b",
95
- "finance": r"\b(budget|invoice|revenue|forecast|profit|loss|roi|margin|cash.?flow|financial|invest|valuation|pricing)\b",
96
- "ecom": r"\b(store|product|shop|shopify|ecommerce|catalog|inventory|cart|checkout|pricing|marketplace)\b",
97
- "strategy": r"\b(strategy|brainstorm|market|swot|competitors?|roadmap|pivot|growth|porter|blue.?ocean|positioning)\b",
93
+ "dev": (
94
+ r"\b("
95
+ r"build|code|feature|deploy|test|review|scaffold|"
96
+ r"debug|refactor|api|migration|stack|implement|fix|"
97
+ r"bug)\b"
98
+ ),
99
+ "marketing": (
100
+ r"\b("
101
+ r"social|content|campaign|post|instagram|linkedin|"
102
+ r"twitter|tiktok|seo|marketing|ads|email.?campaign|"
103
+ r"growth|viral)\b"
104
+ ),
105
+ "finance": (
106
+ r"\b("
107
+ r"budget|invoice|revenue|forecast|profit|loss|roi|"
108
+ r"margin|cash.?flow|financial|invest|valuation|"
109
+ r"pricing)\b"
110
+ ),
111
+ "ecom": (
112
+ r"\b("
113
+ r"store|product|shop|shopify|ecommerce|catalog|"
114
+ r"inventory|cart|checkout|pricing|marketplace)\b"
115
+ ),
116
+ "strategy": (
117
+ r"\b("
118
+ r"strategy|brainstorm|market|swot|competitors?|"
119
+ r"roadmap|pivot|growth|porter|blue.?ocean|"
120
+ r"positioning)\b"
121
+ ),
98
122
  "ops": r"\b(task|automate|meeting|workflow|process|schedule|sop|integration|zapier|n8n)\b",
99
123
  "kb": r"\b(learn|persona|knowledge|youtube|transcribe|article|research|zettelkasten|note)\b",
100
- "brand": r"\b(brand|logo|colors|palette|mockup|photoshoot|brand.?identity|brand.?guide|mood.?board|naming|visual.?design|motion|ux|ui|wireframe)\b",
124
+ "brand": (
125
+ r"\b("
126
+ r"brand|logo|colors|palette|mockup|photoshoot|brand.?identity|"
127
+ r"brand.?guide|mood.?board|naming|visual.?design|motion|ux|ui|"
128
+ r"wireframe)\b"
129
+ ),
101
130
  "saas": r"\b(saas|micro.?saas|plg|freemium|churn|mrr|arr|subscription|onboarding|metrics)\b",
102
- "landing": r"\b(landing|funnel|copy|headline|offer|launch|affiliate|webinar|conversion|sales.?page)\b",
103
- "community": r"\b(community|group|membership|discord|telegram|skool|circle|gamification|engagement)\b",
131
+ "landing": (
132
+ r"\b("
133
+ r"landing|funnel|copy|headline|offer|launch|"
134
+ r"affiliate|webinar|conversion|sales.?page)\b"
135
+ ),
136
+ "community": (
137
+ r"\b("
138
+ r"community|group|membership|discord|"
139
+ r"telegram|skool|circle|gamification|"
140
+ r"engagement)\b"
141
+ ),
104
142
  "content": r"\b(viral|hook|script|repurpose|youtube|tiktok|reels|shorts|newsletter|creator)\b",
105
143
  "pm": r"\b(sprint|backlog|standup|retro|scrum|kanban|story|estimate|roadmap|agile)\b",
106
- "lead": r"\b(leadership|delegation|1on1|feedback|culture|hiring|performance.?review|team.?build)\b",
107
- "sales": r"\b(pipeline|proposal|discovery.?call|objection|negotiate|deal|close|prospect|spin|challenger|cold.?email|outreach)\b",
108
- "org": r"\b(org.?design|hiring.?plan|onboarding|remote|meeting.?optimize|compensation|decision.?framework)\b",
144
+ "lead": (
145
+ r"\b("
146
+ r"leadership|delegation|1on1|feedback|"
147
+ r"culture|hiring|performance.?review|"
148
+ r"team.?build)\b"
149
+ ),
150
+ "sales": (
151
+ r"\b("
152
+ r"pipeline|proposal|discovery.?call|objection|negotiate|"
153
+ r"deal|close|prospect|spin|challenger|cold.?email|"
154
+ r"outreach)\b"
155
+ ),
156
+ "org": (
157
+ r"\b("
158
+ r"org.?design|hiring.?plan|onboarding|remote|"
159
+ r"meeting.?optimize|compensation|"
160
+ r"decision.?framework)\b"
161
+ ),
109
162
  }
110
163
 
111
164
 
@@ -317,10 +370,7 @@ class BranchLayer(Layer):
317
370
  start = time.time()
318
371
  branch = ctx.git_branch
319
372
  # Hide main/master/dev branches
320
- if branch in ("main", "master", "dev", ""):
321
- tag = ""
322
- else:
323
- tag = f"[branch:{branch}]"
373
+ tag = "" if branch in ("main", "master", "dev", "") else f"[branch:{branch}]"
324
374
 
325
375
  ms = int((time.time() - start) * 1000)
326
376
  return LayerResult(
@@ -427,7 +477,7 @@ class QualityGateLayer(Layer):
427
477
  def compute(self, ctx: PromptContext) -> LayerResult:
428
478
  start = time.time()
429
479
  try:
430
- from core.governance.quality_api import list_pending, list_approved
480
+ from core.governance.quality_api import list_approved, list_pending
431
481
 
432
482
  pending = list_pending()
433
483
  approved = list_approved(limit=3)
@@ -496,6 +546,17 @@ class KnowledgeRetrievalLayer(Layer):
496
546
  def cache_ttl(self) -> int:
497
547
  return 30
498
548
 
549
+ @property
550
+ def emits_block(self) -> bool:
551
+ """The retrieved chunks are a real block, not the tag's value.
552
+
553
+ `[knowledge:N chunks]` makes a QUANTIFIED claim about content the
554
+ model never received before the content channel existed — the
555
+ loudest unbacked claim in the tag line (QG review). Opting in
556
+ delivers what the tag advertises.
557
+ """
558
+ return True
559
+
499
560
  @property
500
561
  def priority(self) -> int:
501
562
  return 35
@@ -580,7 +641,10 @@ class KnowledgeRetrievalLayer(Layer):
580
641
  parts.append(f"[cached] {src}: {text}" if src else f"[cached] {text}")
581
642
  parts.extend(snippets)
582
643
 
583
- content = " | ".join(parts)
644
+ # Self-naming, because the content channel delivers this verbatim to
645
+ # the model: an unlabelled `[cached] file.md: …` fragment would read
646
+ # as stray text (the exact defect the opt-in channel exists to avoid).
647
+ content = f"[arka:knowledge] {' | '.join(parts)}" if parts else ""
584
648
  chunk_count = len(snippets) + (len(overlapping) if overlapping else 0)
585
649
  # RAG honesty (PR-3 v4.1): keyword-degraded results must never be
586
650
  # presented as semantic similarity — label the tag explicitly.
@@ -639,7 +703,7 @@ class ForgeContextLayer(Layer):
639
703
  parts = [f"Forge plan: {plan.id} ({plan.status.value})"]
640
704
  if plan.critic.confidence > 0:
641
705
  decisions = []
642
- for source, elements in plan.critic.synthesis.items():
706
+ for _source, elements in plan.critic.synthesis.items():
643
707
  decisions.extend(elements)
644
708
  if decisions:
645
709
  parts.append(f"Decisions: {'; '.join(decisions[:5])}")
@@ -701,7 +765,6 @@ class SessionContextLayer(Layer):
701
765
  layer_id=self.id, tag="", content="", tokens_est=0, compute_ms=0, cached=False
702
766
  )
703
767
 
704
- lines = content.split("\n")
705
768
  tag = "[session:resume]"
706
769
  tokens = len(content.split())
707
770
 
@@ -720,6 +783,8 @@ class SessionContextLayer(Layer):
720
783
  # `core.synapse.layers` import paths and helper references keep working.
721
784
 
722
785
  from core.synapse.layers_kb import ( # noqa: E402,F401
786
+ _KB_CONFIG_PATH,
787
+ _MAX_FALLBACK_NOTES,
723
788
  KBContextLayer,
724
789
  _apply_grounding_policy,
725
790
  _build_note_entry,
@@ -732,10 +797,8 @@ from core.synapse.layers_kb import ( # noqa: E402,F401
732
797
  _hit_is_inferred,
733
798
  _jaccard,
734
799
  _jaccard_fallback,
735
- _KB_CONFIG_PATH,
736
800
  _l25_feature_flag_on,
737
801
  _load_fallback_notes,
738
- _MAX_FALLBACK_NOTES,
739
802
  _note_from_vector_hit,
740
803
  _tokenize_for_jaccard,
741
804
  _vector_search,
@@ -69,6 +69,22 @@ class Layer(ABC):
69
69
  """
70
70
  return False
71
71
 
72
+ @property
73
+ def emits_block(self) -> bool:
74
+ """True when ``content`` is a self-describing full-text block.
75
+
76
+ OPT-IN, and deliberately so. The engine forwards ``content`` to the
77
+ model only for layers that declare this. Inferring it from
78
+ ``content != tag`` looked equivalent and was not: most layers set
79
+ ``content`` to their tag's VALUE (``dev``, ``active``,
80
+ ``feat/plan-canvas``), so every prompt gained stray unlabeled lines
81
+ carrying nothing the tag had not already said (QG review).
82
+
83
+ A block must stand alone: it names itself (``[arka:kb-context]``,
84
+ ``[arka:graph-remote unverified]``) and is meaningful without the tag.
85
+ """
86
+ return False
87
+
72
88
  @property
73
89
  def session_sensitive(self) -> bool:
74
90
  """True when compute() has per-session side effects or output.