loki-mode 6.74.6 → 6.75.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 (70) hide show
  1. package/README.md +1 -53
  2. package/SKILL.md +2 -2
  3. package/VERSION +1 -1
  4. package/autonomy/loki +989 -0
  5. package/autonomy/run.sh +106 -2
  6. package/dashboard/__init__.py +1 -1
  7. package/docs/INSTALLATION.md +1 -1
  8. package/mcp/__init__.py +1 -1
  9. package/mcp/server.py +177 -0
  10. package/package.json +1 -1
  11. package/references/mcp-integration.md +59 -0
  12. package/skills/00-index.md +9 -0
  13. package/skills/documentation.md +123 -0
  14. package/skills/quality-gates.md +25 -1
  15. package/web-app/dist/assets/{AdminPage-Cwqm_kDg.js → AdminPage-D4QSV6Zi.js} +1 -1
  16. package/web-app/dist/assets/{Avatar-BgcFY2E5.js → Avatar-88MlpLO5.js} +1 -1
  17. package/web-app/dist/assets/{Badge-DeFGfZLB.js → Badge-DbGjLr4i.js} +1 -1
  18. package/web-app/dist/assets/{Button-Dg1EkPtN.js → Button-sp_FVGZj.js} +1 -1
  19. package/web-app/dist/assets/{ComparePage-D-wvMVP2.js → ComparePage-p2ENnfa7.js} +1 -1
  20. package/web-app/dist/assets/{GitHubIssuesPanel-B_Jm7CmJ.js → GitHubIssuesPanel-DBbBTG9w.js} +1 -1
  21. package/web-app/dist/assets/{GitHubPRsPanel-B5i8Q99N.js → GitHubPRsPanel-Bi_yrcAE.js} +1 -1
  22. package/web-app/dist/assets/{HomePage-CUDTdntY.js → HomePage-BB83YPiX.js} +1 -1
  23. package/web-app/dist/assets/{LoginPage-BobwVXx5.js → LoginPage-BXUudCJ9.js} +1 -1
  24. package/web-app/dist/assets/{MetricsPage-DmM--20B.js → MetricsPage-CX0Ahy-_.js} +1 -1
  25. package/web-app/dist/assets/{NotFoundPage-6_gjeogD.js → NotFoundPage-C4JqatEk.js} +1 -1
  26. package/web-app/dist/assets/{ProjectPage-C3R2wbFt.js → ProjectPage-t5J2XAJT.js} +46 -46
  27. package/web-app/dist/assets/{ProjectsPage-DQr06iBk.js → ProjectsPage-Bzpz1clk.js} +1 -1
  28. package/web-app/dist/assets/{SettingsPage-eROlGKB9.js → SettingsPage-y_yl8FvH.js} +1 -1
  29. package/web-app/dist/assets/{ShowcasePage-DEA5tT_R.js → ShowcasePage-B7d6pzMq.js} +1 -1
  30. package/web-app/dist/assets/{SystemSettingsPage-C_rIbgZg.js → SystemSettingsPage-C4tR33KU.js} +1 -1
  31. package/web-app/dist/assets/{TeamsPage-DZGoYZnD.js → TeamsPage-DIOCfZIP.js} +1 -1
  32. package/web-app/dist/assets/{TemplatesPage-DVblWpbO.js → TemplatesPage-DlKyapXX.js} +1 -1
  33. package/web-app/dist/assets/{TerminalOutput-DnESY9zk.js → TerminalOutput-Czg-ZC2k.js} +1 -1
  34. package/web-app/dist/assets/{activity-COLsZyo1.js → activity-h1wU9a0L.js} +1 -1
  35. package/web-app/dist/assets/{bell-BjLe9xXk.js → bell-Bu8lsWOp.js} +1 -1
  36. package/web-app/dist/assets/{bot-Dz62aBIi.js → bot-rWO7KjkQ.js} +1 -1
  37. package/web-app/dist/assets/{check-BQPQjkH4.js → check-BWp8L5Cy.js} +1 -1
  38. package/web-app/dist/assets/{chevron-left-BVvOVUQ8.js → chevron-left-Bw4I1yGm.js} +1 -1
  39. package/web-app/dist/assets/{circle-alert-DqoLW238.js → circle-alert-C37PKXiC.js} +1 -1
  40. package/web-app/dist/assets/{clock-Cn9fFUva.js → clock-DDScLol4.js} +1 -1
  41. package/web-app/dist/assets/{cloud-COJxbgUu.js → cloud-DaYKPLaM.js} +1 -1
  42. package/web-app/dist/assets/{copy-DOn0hVgy.js → copy-DKIRv0VK.js} +1 -1
  43. package/web-app/dist/assets/{database-Bj3Llvnk.js → database-CYZBHz51.js} +1 -1
  44. package/web-app/dist/assets/{dollar-sign-BcmncygQ.js → dollar-sign-CydJu0kl.js} +1 -1
  45. package/web-app/dist/assets/{file-code-corner-BysxoSyu.js → file-code-corner-DqZ9gpdv.js} +1 -1
  46. package/web-app/dist/assets/{file-plus-Dwi1MqSS.js → file-plus-CzeFJWp3.js} +1 -1
  47. package/web-app/dist/assets/{folder-open-WzXNCq2x.js → folder-open-4YWk08dP.js} +1 -1
  48. package/web-app/dist/assets/{git-commit-horizontal-D85UUfNF.js → git-commit-horizontal-wbqFPNID.js} +1 -1
  49. package/web-app/dist/assets/{globe-CegT0VaL.js → globe-Cby-g5Yb.js} +1 -1
  50. package/web-app/dist/assets/{hammer-ZGKvu_xy.js → hammer-BNScgGdp.js} +1 -1
  51. package/web-app/dist/assets/{index-_2iPl2nX.js → index-6Z4B0I6r.js} +74 -74
  52. package/web-app/dist/assets/{layers-B40lki5j.js → layers-XfssQc5V.js} +1 -1
  53. package/web-app/dist/assets/{lightbulb-CFSoqUsV.js → lightbulb-EhnzRw7M.js} +1 -1
  54. package/web-app/dist/assets/{loader-circle-womi7Brk.js → loader-circle-BA0QIVGA.js} +1 -1
  55. package/web-app/dist/assets/{lock-CEWBb_SL.js → lock-BABtHe6K.js} +1 -1
  56. package/web-app/dist/assets/{mail-DimGrYf8.js → mail-Dokiey5S.js} +1 -1
  57. package/web-app/dist/assets/{package-DysIuuIJ.js → package-DbJyS1Ft.js} +1 -1
  58. package/web-app/dist/assets/{plus-DG1hW27_.js → plus-BcAN8Kaj.js} +1 -1
  59. package/web-app/dist/assets/{refresh-cw-X31ig0S6.js → refresh-cw-B3dG1-Sb.js} +1 -1
  60. package/web-app/dist/assets/{rotate-ccw-CBXooICo.js → rotate-ccw-Cs1Phctm.js} +1 -1
  61. package/web-app/dist/assets/{save-DQVrWTjZ.js → save-DsrNCZrP.js} +1 -1
  62. package/web-app/dist/assets/{server-BYAMALfa.js → server-CpN2GX4G.js} +1 -1
  63. package/web-app/dist/assets/{shield-alert-B3G7vLiW.js → shield-alert-CKJ1pzCz.js} +1 -1
  64. package/web-app/dist/assets/{trash-2-ChVunC-C.js → trash-2-C9vZqTqw.js} +1 -1
  65. package/web-app/dist/assets/{trending-down-DgsuOE2t.js → trending-down-BNLTrF5P.js} +1 -1
  66. package/web-app/dist/assets/{trending-up-CZHZsGeN.js → trending-up-DmFIdVOc.js} +1 -1
  67. package/web-app/dist/assets/{usePolling-ns_dFCVn.js → usePolling-vUlY-o6P.js} +1 -1
  68. package/web-app/dist/assets/{user-FQUrWHhF.js → user-Dh00W8De.js} +1 -1
  69. package/web-app/dist/index.html +1 -1
  70. package/web-app/server.py +196 -0
package/autonomy/run.sh CHANGED
@@ -2545,7 +2545,8 @@ merge_feature() {
2545
2545
  # Delete branch
2546
2546
  git -C "$TARGET_DIR" branch -d "$branch" 2>/dev/null || true
2547
2547
 
2548
- # Signal for docs update
2548
+ # DOCS_NEEDED signal: triggers the parallel docs worktree to run `loki docs update`
2549
+ # and regenerate documentation for recently changed files.
2549
2550
  mkdir -p "$TARGET_DIR/.loki/signals"
2550
2551
  touch "$TARGET_DIR/.loki/signals/DOCS_NEEDED"
2551
2552
  }
@@ -2655,7 +2656,7 @@ run_parallel_orchestrator() {
2655
2656
 
2656
2657
  # Spawn docs session
2657
2658
  if [ "$PARALLEL_DOCS" = "true" ] && [ -n "${WORKTREE_PATHS[docs]:-}" ]; then
2658
- spawn_worktree_session "docs" "Monitor for DOCS_NEEDED signal. Update documentation for recent changes. Check git log."
2659
+ spawn_worktree_session "docs" "Documentation maintenance stream. Steps: 1) Run 'loki docs generate' if .loki/docs/ does not exist. 2) Watch for .loki/signals/DOCS_NEEDED file. When found, run 'loki docs update' and remove the signal file. 3) After each doc update, run 'loki docs check' and report coverage. 4) Focus on documenting new files, changed APIs, and architectural decisions."
2659
2660
  fi
2660
2661
 
2661
2662
  # Main orchestrator loop
@@ -5695,6 +5696,93 @@ TREOF
5695
5696
  fi
5696
5697
  }
5697
5698
 
5699
+ # ============================================================================
5700
+ # Documentation Staleness Check (v6.75.0)
5701
+ # Checks if generated documentation is stale relative to HEAD
5702
+ # ============================================================================
5703
+
5704
+ run_doc_staleness_check() {
5705
+ local manifest="$TARGET_DIR/.loki/docs/docs-manifest.json"
5706
+ if [ ! -f "$manifest" ]; then
5707
+ log_info "Documentation: No docs generated yet (run 'loki docs generate')"
5708
+ return 0
5709
+ fi
5710
+
5711
+ local doc_sha
5712
+ doc_sha=$(python3 -c "import json; print(json.load(open('$manifest')).get('git_sha', ''))" 2>/dev/null)
5713
+ if [ -z "$doc_sha" ]; then
5714
+ return 0
5715
+ fi
5716
+
5717
+ local commits_behind
5718
+ commits_behind=$(git -C "${TARGET_DIR:-.}" rev-list --count "$doc_sha..HEAD" 2>/dev/null || echo "0")
5719
+
5720
+ if [ "$commits_behind" -gt 10 ]; then
5721
+ log_warn "Documentation is $commits_behind commits behind. Consider running 'loki docs update'."
5722
+ # Emit DOCS_NEEDED signal for the parallel docs worktree
5723
+ mkdir -p "$TARGET_DIR/.loki/signals"
5724
+ touch "$TARGET_DIR/.loki/signals/DOCS_NEEDED"
5725
+ else
5726
+ log_info "Documentation: up to date ($commits_behind commits since last update)"
5727
+ fi
5728
+ }
5729
+
5730
+ # ============================================================================
5731
+ # Documentation Quality Gate - Gate 11 (v6.75.0)
5732
+ # Checks README, documentation freshness, and package API docs
5733
+ # ============================================================================
5734
+
5735
+ run_doc_quality_gate() {
5736
+ local project_dir="${1:-${TARGET_DIR:-.}}"
5737
+ local score=100
5738
+ local issues=()
5739
+
5740
+ # Check 1: README.md exists
5741
+ if [ ! -f "$project_dir/README.md" ] || [ ! -s "$project_dir/README.md" ]; then
5742
+ score=$((score - 20))
5743
+ issues+=("README.md missing or empty")
5744
+ fi
5745
+
5746
+ # Check 2: Documentation freshness
5747
+ local manifest="$project_dir/.loki/docs/docs-manifest.json"
5748
+ if [ -f "$manifest" ]; then
5749
+ local doc_sha
5750
+ doc_sha=$(python3 -c "import json; print(json.load(open('$manifest')).get('git_sha', ''))" 2>/dev/null)
5751
+ if [ -n "$doc_sha" ]; then
5752
+ local behind
5753
+ behind=$(git -C "$project_dir" rev-list --count "$doc_sha..HEAD" 2>/dev/null || echo "0")
5754
+ if [ "$behind" -gt 10 ]; then
5755
+ score=$((score - 15))
5756
+ issues+=("Documentation is $behind commits behind HEAD")
5757
+ fi
5758
+ fi
5759
+ else
5760
+ score=$((score - 10))
5761
+ issues+=("No generated documentation found (run 'loki docs generate')")
5762
+ fi
5763
+
5764
+ # Check 3: Package documentation (for npm/pip packages)
5765
+ if [ -f "$project_dir/package.json" ] || [ -f "$project_dir/setup.py" ] || [ -f "$project_dir/pyproject.toml" ]; then
5766
+ if [ ! -f "$project_dir/.loki/docs/API.md" ]; then
5767
+ score=$((score - 15))
5768
+ issues+=("Package detected but no API documentation generated")
5769
+ fi
5770
+ fi
5771
+
5772
+ # Report
5773
+ if [ ${#issues[@]} -gt 0 ]; then
5774
+ log_warn "Documentation Gate: Score $score/100"
5775
+ for issue in "${issues[@]}"; do
5776
+ log_warn " - $issue"
5777
+ done
5778
+ else
5779
+ log_info "Documentation Gate: PASS (Score $score/100)"
5780
+ fi
5781
+
5782
+ # Gate passes if score >= 70
5783
+ [ "$score" -ge 70 ]
5784
+ }
5785
+
5698
5786
  # ============================================================================
5699
5787
  # 3-Reviewer Parallel Code Review (v5.35.0)
5700
5788
  # Specialist pool from skills/quality-gates.md with blind review
@@ -9982,6 +10070,22 @@ if __name__ == "__main__":
9982
10070
  fi
9983
10071
  fi
9984
10072
  fi
10073
+ # Documentation staleness check (v6.75.0)
10074
+ if [ "$ITERATION_COUNT" -gt 0 ]; then
10075
+ run_doc_staleness_check
10076
+ fi
10077
+ # Documentation quality gate - Gate 11 (v6.75.0)
10078
+ if [ "${LOKI_GATE_DOC_COVERAGE:-true}" = "true" ] && [ "$ITERATION_COUNT" -gt 0 ]; then
10079
+ log_info "Quality gate: documentation coverage..."
10080
+ if run_doc_quality_gate; then
10081
+ clear_gate_failure "doc_coverage"
10082
+ else
10083
+ local dc_count
10084
+ dc_count=$(track_gate_failure "doc_coverage")
10085
+ gate_failures="${gate_failures}doc_coverage,"
10086
+ log_warn "Documentation coverage gate: Score below threshold ($dc_count consecutive)"
10087
+ fi
10088
+ fi
9985
10089
  # Store gate failures for prompt injection
9986
10090
  if [ -n "$gate_failures" ]; then
9987
10091
  echo "$gate_failures" > "${TARGET_DIR:-.}/.loki/quality/gate-failures.txt"
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "6.74.6"
10
+ __version__ = "6.75.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v6.74.6
5
+ **Version:** v6.75.0
6
6
 
7
7
  ---
8
8
 
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '6.74.6'
60
+ __version__ = '6.75.0'
package/mcp/server.py CHANGED
@@ -1739,6 +1739,183 @@ async def mem_get(
1739
1739
  return json.dumps({"error": str(e), "entries": {}})
1740
1740
 
1741
1741
 
1742
+ # ============================================================
1743
+ # GIT INTELLIGENCE TOOLS (Phase 4 - Repowise native equivalent)
1744
+ # ============================================================
1745
+
1746
+ @mcp.tool()
1747
+ async def loki_get_hotspots(
1748
+ limit: int = 10,
1749
+ ) -> str:
1750
+ """Get the most frequently changed files in the repository.
1751
+
1752
+ Identifies code hotspots based on git commit frequency analysis.
1753
+ These files deserve extra care during changes (higher risk of regressions).
1754
+
1755
+ Args:
1756
+ limit: Number of top hotspot files to return (default 10, max 30)
1757
+ """
1758
+ _emit_tool_event_async('loki_get_hotspots', 'start',
1759
+ parameters={'limit': limit})
1760
+
1761
+ limit = min(max(1, limit), 30)
1762
+
1763
+ try:
1764
+ hotspots_path = safe_path_join('.loki', 'intelligence', 'hotspots.txt')
1765
+ except PathTraversalError:
1766
+ _emit_tool_event_async('loki_get_hotspots', 'complete',
1767
+ result_status='error', error='Access denied')
1768
+ return json.dumps({"error": "Access denied"})
1769
+
1770
+ if not os.path.exists(hotspots_path):
1771
+ _emit_tool_event_async('loki_get_hotspots', 'complete',
1772
+ result_status='error', error='Not available')
1773
+ return json.dumps({
1774
+ "error": "Git intelligence not yet generated",
1775
+ "hint": "Run 'loki start' or wait for the next autonomous iteration"
1776
+ })
1777
+
1778
+ try:
1779
+ results = []
1780
+ with open(hotspots_path, 'r') as f:
1781
+ for line in f:
1782
+ line = line.strip()
1783
+ if not line:
1784
+ continue
1785
+ # Format: " 42 path/to/file.py"
1786
+ parts = line.split(None, 1)
1787
+ if len(parts) == 2:
1788
+ try:
1789
+ changes = int(parts[0])
1790
+ except ValueError:
1791
+ continue
1792
+ results.append({"file": parts[1], "changes": changes})
1793
+ if len(results) >= limit:
1794
+ break
1795
+
1796
+ _emit_tool_event_async('loki_get_hotspots', 'complete',
1797
+ result_status='success', result_count=len(results))
1798
+ return json.dumps({"hotspots": results, "total": len(results)})
1799
+ except Exception as e:
1800
+ logger.error(f"loki_get_hotspots failed: {e}")
1801
+ _emit_tool_event_async('loki_get_hotspots', 'complete',
1802
+ result_status='error', error=str(e))
1803
+ return json.dumps({"error": str(e)})
1804
+
1805
+
1806
+ @mcp.tool()
1807
+ async def loki_get_co_changes(
1808
+ file_path: str,
1809
+ ) -> str:
1810
+ """Find files that frequently change together with a given file.
1811
+
1812
+ Uses git co-change analysis to identify coupling between files.
1813
+ Useful for understanding hidden dependencies and ensuring related
1814
+ files are updated together.
1815
+
1816
+ Args:
1817
+ file_path: Path to the file to find co-change partners for
1818
+ """
1819
+ _emit_tool_event_async('loki_get_co_changes', 'start',
1820
+ parameters={'file_path': file_path})
1821
+
1822
+ try:
1823
+ co_changes_path = safe_path_join('.loki', 'intelligence', 'co-changes.json')
1824
+ except PathTraversalError:
1825
+ _emit_tool_event_async('loki_get_co_changes', 'complete',
1826
+ result_status='error', error='Access denied')
1827
+ return json.dumps({"error": "Access denied"})
1828
+
1829
+ if not os.path.exists(co_changes_path):
1830
+ _emit_tool_event_async('loki_get_co_changes', 'complete',
1831
+ result_status='error', error='Not available')
1832
+ return json.dumps({
1833
+ "error": "Git intelligence not yet generated",
1834
+ "hint": "Run 'loki start' or wait for the next autonomous iteration"
1835
+ })
1836
+
1837
+ try:
1838
+ with open(co_changes_path, 'r') as f:
1839
+ pairs = json.load(f)
1840
+
1841
+ # Filter pairs involving the requested file
1842
+ results = []
1843
+ for pair_files, count in pairs:
1844
+ if file_path in pair_files:
1845
+ partner = pair_files[0] if pair_files[1] == file_path else pair_files[1]
1846
+ results.append({"partner": partner, "co_changes": count})
1847
+
1848
+ # Sort by co-change count descending
1849
+ results.sort(key=lambda x: x["co_changes"], reverse=True)
1850
+
1851
+ _emit_tool_event_async('loki_get_co_changes', 'complete',
1852
+ result_status='success', result_count=len(results))
1853
+ return json.dumps({
1854
+ "file": file_path,
1855
+ "co_changed_with": results,
1856
+ "total": len(results)
1857
+ })
1858
+ except Exception as e:
1859
+ logger.error(f"loki_get_co_changes failed: {e}")
1860
+ _emit_tool_event_async('loki_get_co_changes', 'complete',
1861
+ result_status='error', error=str(e))
1862
+ return json.dumps({"error": str(e)})
1863
+
1864
+
1865
+ @mcp.tool()
1866
+ async def loki_get_doc_coverage() -> str:
1867
+ """Get documentation coverage status for the project.
1868
+
1869
+ Reads from the docs manifest to report which files are documented,
1870
+ which have stale documentation, and which are missing docs entirely.
1871
+ Useful for prioritizing documentation work.
1872
+ """
1873
+ _emit_tool_event_async('loki_get_doc_coverage', 'start')
1874
+
1875
+ try:
1876
+ manifest_path = safe_path_join('.loki', 'docs', 'docs-manifest.json')
1877
+ except PathTraversalError:
1878
+ _emit_tool_event_async('loki_get_doc_coverage', 'complete',
1879
+ result_status='error', error='Access denied')
1880
+ return json.dumps({"error": "Access denied"})
1881
+
1882
+ if not os.path.exists(manifest_path):
1883
+ _emit_tool_event_async('loki_get_doc_coverage', 'complete',
1884
+ result_status='error', error='Not available')
1885
+ return json.dumps({
1886
+ "error": "Documentation manifest not found",
1887
+ "hint": "Create .loki/docs/docs-manifest.json with file documentation status"
1888
+ })
1889
+
1890
+ try:
1891
+ with open(manifest_path, 'r') as f:
1892
+ manifest = json.load(f)
1893
+
1894
+ total_files = manifest.get("total_files", 0)
1895
+ documented_files = manifest.get("documented_files", 0)
1896
+ coverage_pct = round((documented_files / total_files * 100) if total_files > 0 else 0, 1)
1897
+
1898
+ stale_docs = manifest.get("stale_docs", [])
1899
+ missing_docs = manifest.get("missing_docs", [])
1900
+
1901
+ result = {
1902
+ "coverage_pct": coverage_pct,
1903
+ "total_files": total_files,
1904
+ "documented_files": documented_files,
1905
+ "stale_docs": stale_docs[:20], # Limit to avoid huge responses
1906
+ "missing_docs": missing_docs[:20],
1907
+ }
1908
+
1909
+ _emit_tool_event_async('loki_get_doc_coverage', 'complete',
1910
+ result_status='success')
1911
+ return json.dumps(result)
1912
+ except Exception as e:
1913
+ logger.error(f"loki_get_doc_coverage failed: {e}")
1914
+ _emit_tool_event_async('loki_get_doc_coverage', 'complete',
1915
+ result_status='error', error=str(e))
1916
+ return json.dumps({"error": str(e)})
1917
+
1918
+
1742
1919
  # ============================================================
1743
1920
  # PROMPTS - Pre-built prompt templates
1744
1921
  # ============================================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "6.74.6",
3
+ "version": "6.75.0",
4
4
  "description": "Loki Mode by Autonomi - Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "agent",
@@ -93,6 +93,60 @@ Model Context Protocol (MCP) servers extend Claude Code's capabilities with spec
93
93
 
94
94
  ---
95
95
 
96
+ ### 3. Repowise - Codebase Intelligence (Recommended)
97
+
98
+ **Purpose:** Deep codebase intelligence through 8 MCP tools. When installed, Loki Mode automatically uses its tools for richer context during builds.
99
+
100
+ **When to use:**
101
+ - First encounter with an unfamiliar codebase
102
+ - Before modifying files with many dependents
103
+ - Architecture documentation and decision history
104
+ - Semantic code search (natural language)
105
+
106
+ **Setup:**
107
+ ```bash
108
+ pip install repowise
109
+ repowise init . # One-time indexing (~25 min)
110
+ ```
111
+
112
+ **Configuration:**
113
+ ```json
114
+ {
115
+ "mcpServers": {
116
+ "repowise": {
117
+ "command": "repowise",
118
+ "args": ["mcp", "--path", "."]
119
+ }
120
+ }
121
+ }
122
+ ```
123
+
124
+ **Tools provided:**
125
+
126
+ | Tool | Purpose | Use Case |
127
+ |------|---------|----------|
128
+ | `get_overview()` | Architecture summary | First call on unfamiliar codebase |
129
+ | `get_context(targets)` | Docs, ownership, decisions | Before modifying files |
130
+ | `get_risk(targets)` | Hotspots, dependents, co-changes | Before modifying files |
131
+ | `get_why(query)` | Decision history | Before architectural changes |
132
+ | `search_codebase(query)` | Natural language code search | Finding code semantically |
133
+ | `get_dependency_path(from, to)` | Trace connections between files | Dependency analysis |
134
+ | `get_dead_code()` | Find unreachable code | Cleanup and refactoring |
135
+ | `get_architecture_diagram(module)` | Generate Mermaid diagrams | Documentation generation |
136
+
137
+ **SDLC Phases:** Bootstrap (overview), Development (context/risk), Documentation (diagrams)
138
+
139
+ **Integration with Loki Mode:**
140
+ When Repowise MCP is detected (via `.claude/mcp.json`), Loki Mode automatically:
141
+ 1. Calls `get_overview()` during the BOOTSTRAP phase
142
+ 2. Calls `get_risk()` before modifying hotspot files
143
+ 3. Calls `get_context()` when loading relevant file context
144
+ 4. Uses `search_codebase()` instead of manual grep for semantic code search
145
+
146
+ See `skills/documentation.md` for documentation generation using Repowise.
147
+
148
+ ---
149
+
96
150
  ## MCP Configuration Location
97
151
 
98
152
  Claude Code reads MCP configuration from:
@@ -114,6 +168,10 @@ Example full configuration:
114
168
  "env": {
115
169
  "PARALLEL_API_KEY": "${PARALLEL_API_KEY}"
116
170
  }
171
+ },
172
+ "repowise": {
173
+ "command": "repowise",
174
+ "args": ["mcp", "--path", "."]
117
175
  }
118
176
  }
119
177
  }
@@ -184,3 +242,4 @@ When evaluating new MCP servers for Loki Mode integration, assess:
184
242
  - [MCP Specification](https://modelcontextprotocol.io/)
185
243
  - [Parallel AI Documentation](https://docs.parallel.ai/)
186
244
  - [Playwright MCP](https://github.com/anthropics/anthropic-quickstarts/tree/main/mcp-playwright)
245
+ - [Repowise](https://repowise.dev/)
@@ -29,6 +29,7 @@
29
29
  | Multi-provider (Codex, Gemini) | `providers.md` |
30
30
  | OpenSpec delta context, brownfield modifications | `openspec-integration.md` |
31
31
  | MiroFish market validation, `--mirofish` flag | `mirofish-integration.md` |
32
+ | Writing/updating documentation, `loki docs` | `documentation.md` |
32
33
  | Legacy healing, modernization, archaeology | `healing.md` |
33
34
  | Plan deepening, knowledge extraction | `compound-learning.md` |
34
35
 
@@ -127,6 +128,14 @@
127
128
  - Risk-driven task ordering
128
129
  - Advisory-only (never gates RARV or Completion Council)
129
130
 
131
+ ### documentation.md
132
+ **When:** Writing/updating documentation, `loki docs` commands, Repowise MCP available
133
+ - Documentation types (README, ARCHITECTURE, API, DECISIONS, etc.)
134
+ - Model selection for doc generation (Sonnet/Haiku/Opus)
135
+ - Repowise MCP integration for codebase intelligence
136
+ - Documentation quality criteria and prompts
137
+ - Fallback to native git analysis when Repowise unavailable
138
+
130
139
  ### compound-learning.md (v5.30.0)
131
140
  **When:** After architecture phase (deepen plan), after verification (extract learnings)
132
141
  - Deepen-plan: 4 parallel research agents enhance plans before implementation
@@ -0,0 +1,123 @@
1
+ # Documentation Skill Module
2
+
3
+ ## Research Foundation
4
+
5
+ | Source | Key Contribution | Citation |
6
+ |--------|-----------------|----------|
7
+ | Repowise | Codebase intelligence via MCP tools (overview, risk, context, search) | [repowise.dev](https://repowise.dev/) |
8
+ | Diátaxis | Documentation system: tutorials, how-to, reference, explanation | [diataxis.fr](https://diataxis.fr/) |
9
+ | Google Developer Docs | Style guide for technical documentation | [developers.google.com/style](https://developers.google.com/style) |
10
+
11
+ ---
12
+
13
+ ## When to Load This Module
14
+
15
+ - Writing or updating documentation
16
+ - Running `loki docs` commands
17
+ - After build completion for doc generation
18
+ - When Repowise MCP is available
19
+ - Architecture documentation tasks
20
+
21
+ ---
22
+
23
+ ## Documentation Types
24
+
25
+ | Type | Description | Trigger |
26
+ |------|-------------|---------|
27
+ | README.md | Project overview, setup, usage | New project or major changes |
28
+ | ARCHITECTURE.md | System design, data flow | Architecture phase |
29
+ | API.md | Public API reference | API changes |
30
+ | SETUP.md | Dev environment setup | Dependency changes |
31
+ | COMPONENTS.md | Per-component docs | New components |
32
+ | TESTING.md | Test strategy, coverage | Test changes |
33
+ | DECISIONS.md | Architectural decisions | Design decisions made |
34
+ | CLAUDE.md | AI agent context | Every iteration |
35
+
36
+ ---
37
+
38
+ ## Model Selection
39
+
40
+ - **Documentation generation:** Sonnet (standard tier)
41
+ - **Doc checking/validation:** Haiku (fast tier)
42
+ - **Architecture documentation:** Opus (planning tier)
43
+
44
+ ---
45
+
46
+ ## Repowise Integration
47
+
48
+ When Repowise MCP tools are available (check tool list for `get_overview`, `get_context`, `get_risk`):
49
+
50
+ 1. Prefer Repowise tools over native file scanning for context gathering
51
+ 2. Use `get_overview()` as the foundation for ARCHITECTURE.md
52
+ 3. Use `get_risk()` to prioritize which components need documentation most
53
+ 4. Use `search_codebase()` for finding related code when documenting
54
+ 5. Use `get_architecture_diagram(module)` for generating Mermaid component diagrams
55
+ 6. Use `get_why(query)` to populate DECISIONS.md with architectural rationale
56
+
57
+ When Repowise is NOT available:
58
+
59
+ 1. Fall back to native git analysis (`loki docs generate`)
60
+ 2. Use file tree scanning for context
61
+ 3. Use `git log` for change history
62
+
63
+ ### Detection
64
+
65
+ Repowise MCP is detected automatically when `.claude/mcp.json` contains a `repowise` server entry. Loki Mode injects Repowise instructions into the build prompt when detected.
66
+
67
+ ---
68
+
69
+ ## Documentation Quality Criteria
70
+
71
+ - **Accuracy:** Matches current code behavior
72
+ - **Completeness:** All public APIs documented
73
+ - **Freshness:** Updated within 10 commits of code changes
74
+ - **Readability:** Clear, concise, follows project conventions
75
+ - **Actionable:** Setup docs enable a new developer to start in <10 min
76
+
77
+ ---
78
+
79
+ ## Prompts
80
+
81
+ ### For README generation
82
+
83
+ ```
84
+ Analyze this project and generate a comprehensive README.md. Include: project name,
85
+ description, features, quick start, installation, usage examples, configuration,
86
+ API reference summary, contributing guidelines, and license. Be concise and practical.
87
+ ```
88
+
89
+ ### For ARCHITECTURE generation
90
+
91
+ ```
92
+ Analyze this project's architecture. Document: system overview, component diagram
93
+ (mermaid), data flow, key design decisions, tech stack rationale, deployment
94
+ architecture, and scaling considerations. Focus on WHY decisions were made, not
95
+ just WHAT exists.
96
+ ```
97
+
98
+ ### For API documentation
99
+
100
+ ```
101
+ Document all public APIs in this project. For each endpoint/function/class:
102
+ signature, parameters with types, return values, examples, error cases. Group by
103
+ module/route. Include curl examples for HTTP APIs.
104
+ ```
105
+
106
+ ### For DECISIONS documentation
107
+
108
+ ```
109
+ Review git history and code comments for architectural decisions. For each decision:
110
+ context (what problem was being solved), decision (what was chosen), rationale
111
+ (why this option), alternatives considered, and consequences. Use ADR format.
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Integration with Other Skills
117
+
118
+ | Skill | Interaction |
119
+ |-------|-------------|
120
+ | `quality-gates.md` | Gate 7 checks documentation freshness |
121
+ | `artifacts.md` | Documentation generation uses artifact patterns |
122
+ | `healing.md` | Healing archaeology feeds into institutional knowledge docs |
123
+ | `agents.md` | `documentation-writer` agent type for parallel doc generation |
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Never ship code without passing all quality gates.**
4
4
 
5
- ## The 10 Quality Gates
5
+ ## The 11 Quality Gates
6
6
 
7
7
  1. **Input Guardrails** - Validate scope, detect injection, check constraints (OpenAI SDK)
8
8
  2. **Static Analysis** - CodeQL, ESLint/Pylint, type checking
@@ -14,6 +14,7 @@
14
14
  8. **Mock Detector** - Classifies internal vs external mocks; flags tests that never import source code, tautological assertions, and high internal mock ratios
15
15
  9. **Test Mutation Detector** - Detects assertion value changes alongside implementation changes (test fitting), low assertion density, and missing pass/fail tracking
16
16
  10. **Backward Compatibility** - Behavioral preservation, friction safety, institutional knowledge retention (healing mode)
17
+ 11. **Documentation Coverage** - README exists, docs freshness within 10 commits, API docs for packages
17
18
 
18
19
  ## Gate 10: Backward Compatibility & Behavioral Preservation (v6.67.0)
19
20
 
@@ -42,6 +43,29 @@ LOKI_GATE_BACKWARD_COMPAT=false # Disable gate 10
42
43
 
43
44
  ---
44
45
 
46
+ ## Gate 11: Documentation Coverage (v6.75.0)
47
+
48
+ **Triggers when:** Diff touches public APIs, new files added, library/package releases
49
+
50
+ **Checks:**
51
+ - Every exported function/class/endpoint has a doc entry in `.loki/docs/`
52
+ - README.md exists and is non-empty in project root
53
+ - Documentation SHA is within 10 commits of HEAD
54
+ - CLAUDE.md (if exists) references current key files
55
+
56
+ **Severity:**
57
+ - Missing API docs = Medium (BLOCK for npm/pip packages)
58
+ - Stale docs = Low (TODO)
59
+
60
+ **Skip:** Internal-only changes, test-only changes, config changes
61
+
62
+ **Disabling (not recommended for packages):**
63
+ ```bash
64
+ LOKI_GATE_DOC_COVERAGE=false # Disable gate 11
65
+ ```
66
+
67
+ ---
68
+
45
69
  ## Gate 8 and 9: Automated Test Integrity
46
70
 
47
71
  Gates 8 (Mock Detector) and 9 (Test Mutation Detector) run during the VERIFY phase and are enabled by default.
@@ -1,4 +1,4 @@
1
- import{c as L,j as e,r as m,v as _,Z as Q,m as X,h as ee,b as R,F as ge,U as z,X as te,L as se,w as je,M as fe,T as G,S as be,l as ae,k as ne,x as ve,E as Ee,Q as Ne,Y as re}from"./index-_2iPl2nX.js";import{B as w}from"./Button-Dg1EkPtN.js";import{T as ye}from"./trending-up-CZHZsGeN.js";import{C as I}from"./clock-Cn9fFUva.js";import{A as ke,U as ie}from"./Avatar-BgcFY2E5.js";import{A as H}from"./activity-COLsZyo1.js";import{R as le}from"./refresh-cw-X31ig0S6.js";import{G as Ae}from"./globe-CegT0VaL.js";import{C as we}from"./chevron-left-BVvOVUQ8.js";import{M as Ce}from"./mail-DimGrYf8.js";import{C as ce}from"./check-BQPQjkH4.js";import{D as W}from"./dollar-sign-BcmncygQ.js";import{U as Se}from"./user-FQUrWHhF.js";import{D as De}from"./database-Bj3Llvnk.js";import{L as Fe}from"./lock-CEWBb_SL.js";import{H as Me}from"./hammer-ZGKvu_xy.js";import{S as Be}from"./shield-alert-B3G7vLiW.js";import{S as $e}from"./server-BYAMALfa.js";/**
1
+ import{c as L,j as e,r as m,v as _,Z as Q,m as X,h as ee,b as R,F as ge,U as z,X as te,L as se,w as je,M as fe,T as G,S as be,l as ae,k as ne,x as ve,E as Ee,Q as Ne,Y as re}from"./index-6Z4B0I6r.js";import{B as w}from"./Button-sp_FVGZj.js";import{T as ye}from"./trending-up-DmFIdVOc.js";import{C as I}from"./clock-DDScLol4.js";import{A as ke,U as ie}from"./Avatar-88MlpLO5.js";import{A as H}from"./activity-h1wU9a0L.js";import{R as le}from"./refresh-cw-B3dG1-Sb.js";import{G as Ae}from"./globe-Cby-g5Yb.js";import{C as we}from"./chevron-left-Bw4I1yGm.js";import{M as Ce}from"./mail-Dokiey5S.js";import{C as ce}from"./check-BWp8L5Cy.js";import{D as W}from"./dollar-sign-CydJu0kl.js";import{U as Se}from"./user-Dh00W8De.js";import{D as De}from"./database-CYZBHz51.js";import{L as Fe}from"./lock-BABtHe6K.js";import{H as Me}from"./hammer-BNScgGdp.js";import{S as Be}from"./shield-alert-CKJ1pzCz.js";import{S as $e}from"./server-CpN2GX4G.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as h,j as s}from"./index-_2iPl2nX.js";/**
1
+ import{c as h,j as s}from"./index-6Z4B0I6r.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{j as e}from"./index-_2iPl2nX.js";import{C as r}from"./clock-Cn9fFUva.js";import{C as a}from"./circle-alert-DqoLW238.js";import{C as l}from"./check-BQPQjkH4.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
1
+ import{j as e}from"./index-6Z4B0I6r.js";import{C as r}from"./clock-DDScLol4.js";import{C as a}from"./circle-alert-C37PKXiC.js";import{C as l}from"./check-BWp8L5Cy.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
@@ -1 +1 @@
1
- import{r as p,j as t}from"./index-_2iPl2nX.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
1
+ import{r as p,j as t}from"./index-6Z4B0I6r.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};