woods 1.6.1 → 2.0.0.beta2

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 (274) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2035 -0
  3. data/CONTRIBUTING.md +253 -87
  4. data/README.md +161 -513
  5. data/SECURITY.md +92 -0
  6. data/assets/woods-wordmark-white-with-bg.png +0 -0
  7. data/docs/AGENT_GUIDE.md +204 -0
  8. data/docs/AGENT_SETUP.md +205 -0
  9. data/docs/BACKEND_MATRIX.md +470 -0
  10. data/docs/CONFIGURATION_REFERENCE.md +655 -0
  11. data/docs/CONSOLE_MCP_SETUP.md +829 -0
  12. data/docs/DOCKER_SETUP.md +454 -0
  13. data/docs/EMBEDDING_MODELS.md +136 -0
  14. data/docs/EVALUATION.md +91 -0
  15. data/docs/EXTRACTOR_REFERENCE.md +765 -0
  16. data/docs/FAQ.md +544 -0
  17. data/docs/GETTING_STARTED.md +183 -0
  18. data/docs/INCREMENTAL_EXTRACTION.md +455 -0
  19. data/docs/INTERNALS.md +418 -0
  20. data/docs/MCP_HTTP_TRANSPORT.md +144 -0
  21. data/docs/MCP_SERVERS.md +231 -0
  22. data/docs/MCP_TOOL_COOKBOOK.md +987 -0
  23. data/docs/MCP_WORKTREE_SETUP.md +127 -0
  24. data/docs/NOTION_INTEGRATION.md +283 -0
  25. data/docs/OBSIDIAN_INTEGRATION.md +170 -0
  26. data/docs/PUBLISHED_INDEX.md +213 -0
  27. data/docs/README.md +94 -0
  28. data/docs/RETRIEVAL_GUIDE.md +267 -0
  29. data/docs/TOKEN_BENCHMARK.md +68 -0
  30. data/docs/TROUBLESHOOTING.md +841 -0
  31. data/docs/UNBLOCKED_INTEGRATION.md +279 -0
  32. data/docs/UPGRADING_TO_2.md +321 -0
  33. data/docs/WATCH_DAEMON.md +667 -0
  34. data/docs/WHY_WOODS.md +219 -0
  35. data/exe/woods-console +40 -4
  36. data/exe/woods-console-mcp +21 -35
  37. data/exe/woods-mcp +20 -7
  38. data/exe/woods-mcp-http +80 -11
  39. data/exe/woods-mcp-start +57 -52
  40. data/lib/generators/woods/install_generator.rb +6 -5
  41. data/lib/generators/woods/pgvector_generator.rb +6 -3
  42. data/lib/generators/woods/templates/add_pgvector_to_woods.rb.erb +29 -9
  43. data/lib/generators/woods/templates/create_woods_tables.rb.erb +5 -1
  44. data/lib/generators/woods/templates/woods.rb.tt +49 -28
  45. data/lib/tasks/woods.rake +622 -168
  46. data/lib/tasks/woods_checks.rake +107 -0
  47. data/lib/tasks/woods_evaluation.rake +164 -80
  48. data/lib/woods/ast/call_site_extractor.rb +6 -15
  49. data/lib/woods/ast/method_extractor.rb +19 -9
  50. data/lib/woods/ast/parser.rb +54 -8
  51. data/lib/woods/atomic_file.rb +171 -2
  52. data/lib/woods/builder.rb +310 -22
  53. data/lib/woods/cache/cache_middleware.rb +7 -2
  54. data/lib/woods/cache/cache_store.rb +9 -1
  55. data/lib/woods/cache/solid_cache_store.rb +6 -4
  56. data/lib/woods/change_set.rb +88 -0
  57. data/lib/woods/checks/generation_resolution.rb +34 -0
  58. data/lib/woods/checks/moved_messages.rb +186 -0
  59. data/lib/woods/chunking/semantic_chunker.rb +160 -18
  60. data/lib/woods/console/audit_logger.rb +12 -3
  61. data/lib/woods/console/bridge_protocol.rb +3 -16
  62. data/lib/woods/console/connection_manager.rb +51 -136
  63. data/lib/woods/console/dispatch_pipeline.rb +42 -12
  64. data/lib/woods/console/embedded_executor.rb +806 -149
  65. data/lib/woods/console/eval_guard.rb +27 -20
  66. data/lib/woods/console/input_contract.rb +78 -0
  67. data/lib/woods/console/model_validator.rb +29 -1
  68. data/lib/woods/console/rack_middleware.rb +65 -42
  69. data/lib/woods/console/redactor.rb +26 -8
  70. data/lib/woods/console/safe_context.rb +58 -10
  71. data/lib/woods/console/scope_predicate_parser.rb +41 -0
  72. data/lib/woods/console/server.rb +119 -247
  73. data/lib/woods/console/sql_noise_stripper.rb +125 -16
  74. data/lib/woods/console/sql_table_scanner.rb +82 -22
  75. data/lib/woods/console/sql_validator.rb +459 -29
  76. data/lib/woods/console/table_gate.rb +2 -2
  77. data/lib/woods/console/tool_specs.rb +463 -90
  78. data/lib/woods/console/tools/tier1.rb +1 -5
  79. data/lib/woods/console/tools/tier4.rb +18 -9
  80. data/lib/woods/coordination/lock_heartbeat.rb +103 -0
  81. data/lib/woods/coordination/pipeline_lock.rb +263 -53
  82. data/lib/woods/db/migrations/007_typed_snapshot_units.rb +45 -0
  83. data/lib/woods/db/migrator.rb +3 -9
  84. data/lib/woods/db/schema_version.rb +47 -2
  85. data/lib/woods/dependency_graph.rb +898 -64
  86. data/lib/woods/embedding/fake.rb +138 -0
  87. data/lib/woods/embedding/indexer.rb +832 -40
  88. data/lib/woods/embedding/openai.rb +77 -19
  89. data/lib/woods/embedding/provider.rb +189 -11
  90. data/lib/woods/embedding/text_preparer.rb +1 -1
  91. data/lib/woods/embedding/token_counter.rb +0 -7
  92. data/lib/woods/evaluation/ablation_agent_payload.rb +38 -0
  93. data/lib/woods/evaluation/ablation_executor.rb +67 -0
  94. data/lib/woods/evaluation/ablation_provenance.rb +38 -0
  95. data/lib/woods/evaluation/ablation_report_writer.rb +43 -0
  96. data/lib/woods/evaluation/ablation_runner.rb +173 -0
  97. data/lib/woods/evaluation/ablation_summary.rb +65 -0
  98. data/lib/woods/evaluation/ablation_task.rb +66 -0
  99. data/lib/woods/evaluation/ablation_task_set.rb +77 -0
  100. data/lib/woods/evaluation/ablation_timed_executor.rb +91 -0
  101. data/lib/woods/evaluation/ablation_worktree.rb +71 -0
  102. data/lib/woods/evaluation/baseline.rb +60 -0
  103. data/lib/woods/evaluation/baseline_runner.rb +11 -3
  104. data/lib/woods/evaluation/evaluator.rb +41 -8
  105. data/lib/woods/evaluation/query_set.rb +79 -13
  106. data/lib/woods/evaluation/report_generator.rb +20 -1
  107. data/lib/woods/export/unit_facts.rb +0 -11
  108. data/lib/woods/extracted_unit.rb +22 -63
  109. data/lib/woods/extractor.rb +2783 -238
  110. data/lib/woods/extractors/action_cable_extractor.rb +9 -4
  111. data/lib/woods/extractors/ast_source_extraction.rb +20 -2
  112. data/lib/woods/extractors/caching_extractor.rb +46 -12
  113. data/lib/woods/extractors/callback_analyzer.rb +39 -9
  114. data/lib/woods/extractors/component_discovery.rb +123 -0
  115. data/lib/woods/extractors/concern_extractor.rb +17 -3
  116. data/lib/woods/extractors/controller_extractor.rb +389 -29
  117. data/lib/woods/extractors/decorator_extractor.rb +7 -14
  118. data/lib/woods/extractors/engine_extractor.rb +53 -8
  119. data/lib/woods/extractors/event_extractor.rb +55 -4
  120. data/lib/woods/extractors/factory_extractor.rb +49 -11
  121. data/lib/woods/extractors/graphql_extractor.rb +162 -66
  122. data/lib/woods/extractors/i18n_extractor.rb +6 -1
  123. data/lib/woods/extractors/job_extractor.rb +51 -21
  124. data/lib/woods/extractors/lib_extractor.rb +23 -17
  125. data/lib/woods/extractors/line_neutralizer.rb +171 -0
  126. data/lib/woods/extractors/mailer_extractor.rb +9 -1
  127. data/lib/woods/extractors/manager_extractor.rb +19 -2
  128. data/lib/woods/extractors/migration_extractor.rb +22 -11
  129. data/lib/woods/extractors/model_extractor.rb +292 -57
  130. data/lib/woods/extractors/package_extractor.rb +154 -0
  131. data/lib/woods/extractors/phlex_extractor.rb +18 -3
  132. data/lib/woods/extractors/policy_extractor.rb +6 -5
  133. data/lib/woods/extractors/poro_extractor.rb +13 -14
  134. data/lib/woods/extractors/pundit_extractor.rb +3 -3
  135. data/lib/woods/extractors/rails_source_extractor.rb +24 -7
  136. data/lib/woods/extractors/rake_task_extractor.rb +158 -30
  137. data/lib/woods/extractors/reference_patterns.rb +38 -0
  138. data/lib/woods/extractors/route_extractor.rb +58 -2
  139. data/lib/woods/extractors/scheduled_job_extractor.rb +51 -35
  140. data/lib/woods/extractors/serializer_extractor.rb +3 -4
  141. data/lib/woods/extractors/service_extractor.rb +11 -1
  142. data/lib/woods/extractors/shared_dependency_scanner.rb +24 -34
  143. data/lib/woods/extractors/shared_utility_methods.rb +36 -6
  144. data/lib/woods/extractors/source_nesting.rb +560 -0
  145. data/lib/woods/extractors/state_machine_extractor.rb +30 -18
  146. data/lib/woods/extractors/test_mapping_extractor.rb +26 -9
  147. data/lib/woods/extractors/view_component_extractor.rb +28 -3
  148. data/lib/woods/extractors/view_engines/erb.rb +17 -3
  149. data/lib/woods/feedback/gap_detector.rb +9 -3
  150. data/lib/woods/feedback/store.rb +7 -1
  151. data/lib/woods/filename_utils.rb +29 -1
  152. data/lib/woods/flow_analysis/operation_extractor.rb +22 -10
  153. data/lib/woods/flow_assembler.rb +147 -26
  154. data/lib/woods/flow_document.rb +1 -0
  155. data/lib/woods/flow_precomputer.rb +175 -22
  156. data/lib/woods/gem_mapper.rb +285 -0
  157. data/lib/woods/generation.rb +185 -0
  158. data/lib/woods/git_command.rb +38 -0
  159. data/lib/woods/git_provenance.rb +16 -2
  160. data/lib/woods/graph_analyzer.rb +564 -87
  161. data/lib/woods/index_artifact.rb +93 -23
  162. data/lib/woods/mcp/bearer_auth.rb +102 -13
  163. data/lib/woods/mcp/bootstrap_state.rb +77 -0
  164. data/lib/woods/mcp/bootstrapper.rb +582 -77
  165. data/lib/woods/mcp/config_resolver.rb +66 -6
  166. data/lib/woods/mcp/errors.rb +60 -0
  167. data/lib/woods/mcp/index_reader.rb +836 -117
  168. data/lib/woods/mcp/index_reader_pinning.rb +78 -0
  169. data/lib/woods/mcp/origin_guard.rb +66 -7
  170. data/lib/woods/mcp/protocol_policy.rb +98 -0
  171. data/lib/woods/mcp/provider_probe.rb +45 -6
  172. data/lib/woods/mcp/renderers/markdown_renderer.rb +72 -4
  173. data/lib/woods/mcp/renderers/plain_renderer.rb +54 -6
  174. data/lib/woods/mcp/server.rb +898 -152
  175. data/lib/woods/mcp/tasks/extension.rb +196 -0
  176. data/lib/woods/mcp/tasks/request_capture.rb +45 -0
  177. data/lib/woods/mcp/tasks/store.rb +518 -0
  178. data/lib/woods/mcp/tool_contract.rb +171 -0
  179. data/lib/woods/mcp/tool_response_renderer.rb +7 -0
  180. data/lib/woods/model_name_cache.rb +19 -1
  181. data/lib/woods/notion/client.rb +132 -36
  182. data/lib/woods/notion/exporter.rb +456 -61
  183. data/lib/woods/notion/mappers/column_mapper.rb +34 -5
  184. data/lib/woods/notion/mappers/migration_mapper.rb +32 -8
  185. data/lib/woods/notion/mappers/model_mapper.rb +21 -6
  186. data/lib/woods/notion/mappers/shared.rb +45 -3
  187. data/lib/woods/notion/sync_manifest.rb +258 -0
  188. data/lib/woods/obsidian/errors.rb +6 -0
  189. data/lib/woods/obsidian/name_mapper.rb +40 -24
  190. data/lib/woods/obsidian/vault_exporter.rb +103 -36
  191. data/lib/woods/operator/pipeline_guard.rb +118 -21
  192. data/lib/woods/operator/status_reporter.rb +20 -3
  193. data/lib/woods/path_dispatcher.rb +276 -0
  194. data/lib/woods/payload_store.rb +236 -0
  195. data/lib/woods/published_index/edge_shaper.rb +61 -0
  196. data/lib/woods/published_index/generation_catalog.rb +72 -0
  197. data/lib/woods/published_index/typed_unit_reader.rb +48 -0
  198. data/lib/woods/published_index.rb +287 -0
  199. data/lib/woods/railtie.rb +69 -30
  200. data/lib/woods/railtie_support.rb +167 -0
  201. data/lib/woods/release.rb +12 -0
  202. data/lib/woods/reload_policy.rb +206 -0
  203. data/lib/woods/resilience/circuit_breaker.rb +47 -8
  204. data/lib/woods/resilience/index_validator.rb +296 -10
  205. data/lib/woods/resilience/retryable_provider.rb +71 -6
  206. data/lib/woods/resolved_config.rb +55 -11
  207. data/lib/woods/retrieval/context_assembler.rb +132 -40
  208. data/lib/woods/retrieval/query_classifier.rb +26 -8
  209. data/lib/woods/retrieval/ranker.rb +193 -28
  210. data/lib/woods/retrieval/search_executor.rb +206 -39
  211. data/lib/woods/retriever.rb +317 -71
  212. data/lib/woods/retry_after.rb +22 -2
  213. data/lib/woods/ruby_analyzer/class_analyzer.rb +10 -14
  214. data/lib/woods/ruby_analyzer/fqn_builder.rb +2 -0
  215. data/lib/woods/ruby_analyzer/mermaid_renderer.rb +14 -4
  216. data/lib/woods/ruby_analyzer/method_analyzer.rb +1 -1
  217. data/lib/woods/ruby_analyzer/trace_enricher.rb +3 -0
  218. data/lib/woods/ruby_analyzer.rb +21 -5
  219. data/lib/woods/session_tracer/file_store.rb +138 -19
  220. data/lib/woods/session_tracer/middleware.rb +1 -2
  221. data/lib/woods/session_tracer/redis_store.rb +122 -12
  222. data/lib/woods/session_tracer/session_flow_assembler.rb +57 -17
  223. data/lib/woods/session_tracer/session_flow_document.rb +56 -14
  224. data/lib/woods/session_tracer/solid_cache_coordination.rb +192 -0
  225. data/lib/woods/session_tracer/solid_cache_store.rb +560 -91
  226. data/lib/woods/session_tracer/store.rb +14 -1
  227. data/lib/woods/storage/metadata_store.rb +230 -26
  228. data/lib/woods/storage/pgvector.rb +180 -22
  229. data/lib/woods/storage/qdrant.rb +367 -41
  230. data/lib/woods/storage/snapshotter/metadata.rb +79 -16
  231. data/lib/woods/storage/snapshotter/vector.rb +128 -17
  232. data/lib/woods/storage/snapshotter.rb +23 -5
  233. data/lib/woods/storage/vector_store.rb +49 -8
  234. data/lib/woods/storage_identity.rb +28 -0
  235. data/lib/woods/tasks.rb +53 -2
  236. data/lib/woods/temporal/json_snapshot_store.rb +112 -42
  237. data/lib/woods/temporal/snapshot_store.rb +139 -42
  238. data/lib/woods/unblocked/client.rb +119 -17
  239. data/lib/woods/unblocked/document_builder.rb +34 -2
  240. data/lib/woods/unblocked/exporter.rb +63 -27
  241. data/lib/woods/unblocked/rate_limiter.rb +23 -9
  242. data/lib/woods/unblocked/sync_manifest.rb +16 -8
  243. data/lib/woods/update_check.rb +24 -1
  244. data/lib/woods/util/uuid5.rb +124 -0
  245. data/lib/woods/version.rb +1 -1
  246. data/lib/woods/watch/daemon.rb +1345 -0
  247. data/lib/woods/watch/listen_watcher.rb +81 -0
  248. data/lib/woods/watch/polling_watcher.rb +137 -0
  249. data/lib/woods/watch/status.rb +169 -0
  250. data/lib/woods/watch/tree_scan.rb +163 -0
  251. data/lib/woods/watch/watcher.rb +100 -0
  252. data/lib/woods.rb +138 -9
  253. data/plugin/.claude-plugin/plugin.json +18 -0
  254. data/plugin/hooks/hooks.json +29 -0
  255. data/plugin/hooks/woods-post-edit.sh +226 -0
  256. data/plugin/hooks/woods-session-start.sh +77 -0
  257. data/plugin/skills/woods-agent-enable/SKILL.md +51 -0
  258. data/plugin/skills/woods-diagnose/SKILL.md +75 -0
  259. data/plugin/skills/woods-investigate/SKILL.md +39 -0
  260. data/plugin/skills/woods-mcp-config/SKILL.md +101 -0
  261. data/plugin/skills/woods-setup/SKILL.md +99 -0
  262. metadata +134 -23
  263. data/lib/woods/console/adapters/cache_adapter.rb +0 -58
  264. data/lib/woods/console/adapters/good_job_adapter.rb +0 -33
  265. data/lib/woods/console/adapters/job_adapter.rb +0 -74
  266. data/lib/woods/console/adapters/sidekiq_adapter.rb +0 -33
  267. data/lib/woods/console/adapters/solid_queue_adapter.rb +0 -33
  268. data/lib/woods/console/bridge.rb +0 -210
  269. data/lib/woods/formatting/claude_adapter.rb +0 -98
  270. data/lib/woods/formatting/generic_adapter.rb +0 -56
  271. data/lib/woods/formatting/gpt_adapter.rb +0 -64
  272. data/lib/woods/notion/mapper.rb +0 -40
  273. data/lib/woods/observability/health_check.rb +0 -79
  274. data/lib/woods/observability/instrumentation.rb +0 -34
data/SECURITY.md ADDED
@@ -0,0 +1,92 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported | Until |
6
+ |---------|-----------|-------|
7
+ | 2.0.x | Yes, all fixes | Current release line |
8
+ | 1.6.x | Security fixes only | 2027-02-20 |
9
+ | < 1.6 | No | n/a |
10
+ | 0.x | No | n/a |
11
+
12
+ Only the newest patch release of a supported line receives fixes. A report
13
+ against 1.6.x is assessed against `main` first; if the current release line is
14
+ unaffected, the 1.6.x backport is still issued until the date above.
15
+
16
+ Upgrading from 1.x to 2.0 requires one clean re-index, see the Upgrade Notes in
17
+ [CHANGELOG.md](CHANGELOG.md) and [docs/UPGRADING_TO_2.md](docs/UPGRADING_TO_2.md).
18
+
19
+ ## Reporting a Vulnerability
20
+
21
+ If you discover a security vulnerability in Woods, please report it responsibly.
22
+
23
+ **Do not open a public GitHub issue for security vulnerabilities.**
24
+
25
+ Preferred: use GitHub's private vulnerability reporting, the **Report a
26
+ vulnerability** button under the repository's
27
+ [Security tab](https://github.com/lost-in-the/woods/security/advisories/new).
28
+ It keeps the report, the discussion and the eventual advisory in one place, and
29
+ it does not expose anything publicly until an advisory is published.
30
+
31
+ If you cannot use GitHub, contact the maintainer privately through the address listed in the gem metadata.
32
+
33
+ Either way, please include:
34
+
35
+ 1. A description of the vulnerability
36
+ 2. Steps to reproduce
37
+ 3. The potential impact
38
+ 4. The Woods version and Rails version you observed it on
39
+ 5. Any suggested fix (optional)
40
+
41
+ ## What to Expect
42
+
43
+ - **Acknowledgment** within 48 hours of your report
44
+ - **Assessment** within 1 week, we'll confirm whether it's a valid vulnerability and its severity
45
+ - **Fix timeline** depends on severity:
46
+ - **Critical** (remote code execution, data exfiltration): Patch within 7 days
47
+ - **High** (privilege escalation, injection): Patch within 14 days
48
+ - **Medium/Low** (information disclosure, DoS): Patch in the next release
49
+
50
+ ## Disclosure Timeline
51
+
52
+ - We follow a 90-day coordinated disclosure timeline
53
+ - We'll credit you in the release notes (unless you prefer to remain anonymous)
54
+ - We'll publish a security advisory on GitHub once the fix is released
55
+
56
+ ## Security Considerations
57
+
58
+ Woods runs inside your Rails application and has access to:
59
+
60
+ - **Application source code**: extracted and written to the output directory as JSON
61
+ - **Database schema**: column names, types, indexes, and foreign keys (no row data)
62
+ - **Git metadata**: commit history, contributors, file change frequency
63
+ - **Runtime state** (Console MCP Server only), live database queries within a rolled-back transaction
64
+
65
+ ### Output Directory
66
+
67
+ Extracted data is written to `tmp/woods/` by default. This directory contains your application's source code and schema in structured JSON format. Treat it with the same sensitivity as your source code, do not expose it to untrusted parties.
68
+
69
+ ### Console Server
70
+
71
+ The Console MCP Server provides live database access through a five-layer defense-in-depth stack (feature gate, blocked tables, credential scanner, column redaction, and SqlValidator + rolled-back transactions). Only 9 read-only tools register by default; the optional Tier 4 read tools (`console_sql`, `console_query`) require explicit opt-in via `console_embedded_read_tools` and are constrained by `SqlValidator`'s read-only function allowlist plus rolled-back transactions. No executable tool requires confirmation or writes a privileged audit log, the confirmation/audit contracts belong to Tier 2/3 and `console_eval`, which are inventory-only and never registered. Rolled-back transactions do not undo async side effects (`perform_later`, `deliver_later`, HTTP egress), so treat the Console Server as an admin-trust boundary, not a sandbox: use it in development/staging only, never in production. See [docs/CONSOLE_MCP_SETUP.md. Safety Model](docs/CONSOLE_MCP_SETUP.md#safety-model) for the full breakdown.
72
+
73
+ ### MCP Transport
74
+
75
+ The MCP Index Server supports both stdio and HTTP transports. stdio is the default and has no network exposure. The HTTP transport (`exe/woods-mcp-http`) refuses to bind a non-loopback host unless `WOODS_MCP_HTTP_TOKEN` is set and validates incoming `Authorization: Bearer …` headers. It also enforces a default `Origin` allow-list via `OriginGuard` to mitigate DNS-rebinding attacks. TLS is not terminated in-process, front the HTTP transport with a reverse proxy (nginx, caddy) when exposing it beyond loopback. See [docs/MCP_HTTP_TRANSPORT.md](docs/MCP_HTTP_TRANSPORT.md) for the full deployment guide.
76
+
77
+ ## Blast Radius
78
+
79
+ If extraction output leaks, what can an attacker do with it?
80
+
81
+ **What the output contains.** Application source code (inlined concerns, callback-resolved behavior), database schema (column names, types, indexes, foreign keys), route tables, migration history, gem versions, and git metadata (commit history, contributor emails, file change frequency).
82
+
83
+ **What the output does not contain.** No row-level data from your database. Woods extracts schema only. No environment variables, no `Rails.application.credentials`, no API keys, no session state, no request logs, no customer data.
84
+
85
+ | Leak scenario | Attacker gains | Attacker does not gain |
86
+ |---|---|---|
87
+ | `tmp/woods/` directory exfiltrated | Source code + schema equivalent to a git clone + `rails db:schema:dump` | Database rows, secrets, tokens, customer data |
88
+ | MCP Index Server token leaked (HTTP transport) | Read-only query access to the extracted index, no write or execution paths | Shell access, database row data, secrets |
89
+ | Notion sync database compromised | Model and column summaries synced to Notion | Anything not mirrored, source code stays local |
90
+ | Console MCP Server exposed (dev/staging) | Read-only database access through a rolled-back transaction, bounded by TableGate + Redactor + SqlValidator | Write access (rolled back), full credentials (redacted), blocked tables |
91
+
92
+ **Mitigation.** Treat `tmp/woods/` as source-equivalent, keep it out of world-readable directories and public container images. Rotate `WOODS_MCP_HTTP_TOKEN` on compromise. Keep `console_mcp_enabled = false` in production regardless of environment, since the console layers are defense-in-depth and not primary controls.
@@ -0,0 +1,204 @@
1
+ # Woods agent guide
2
+
3
+ This guide is for coding agents using an already connected Woods MCP server. Woods is evidence from the running Rails application and its extracted graph; it complements file search, tests, git history, and direct source inspection.
4
+
5
+ ## Start every session with status
6
+
7
+ Call `woods_status` before relying on the index. Check:
8
+
9
+ - the index is ready and has a current generation;
10
+ - unit counts are non-zero for relevant types;
11
+ - retrieval is enabled before choosing `codebase_retrieve`;
12
+ - warnings do not indicate a stale or partial index.
13
+
14
+ If status is unhealthy, report the evidence and ask the owner to extract or refresh. Do not fill gaps by asserting that Woods found nothing.
15
+
16
+ ## The default query loop
17
+
18
+ Use this four-step loop for most codebase questions:
19
+
20
+ 1. **Discover** with `search` when you do not know the exact identifier.
21
+ 2. **Inspect** the best match with `lookup`.
22
+ 3. **Traverse** from that identifier with `dependencies`, `dependents`, or `trace_flow`.
23
+ 4. **Verify** important claims against the returned source paths and current repository files.
24
+
25
+ Identifiers are namespaced and typed. Never invent one from a filename when `search` can return the exact value.
26
+
27
+ ## Pick the smallest useful tool
28
+
29
+ | Need | Start with | Continue with |
30
+ |---|---|---|
31
+ | Find a class, route, callback, or phrase | `search` | `lookup` |
32
+ | Understand one exact unit | `lookup` | `dependencies` or `dependents` |
33
+ | Find what a change may break | `dependents` | `trace_flow`, then tests/source |
34
+ | Understand what a unit calls or includes | `dependencies` | `lookup` on important nodes |
35
+ | Follow request-to-model-to-view/job behavior | `trace_flow` | `lookup` at ambiguous steps |
36
+ | Understand a unit's neighborhood | `structure` | targeted traversal |
37
+ | Inspect Rails or gem behavior | `framework` | current source files |
38
+ | Find recently changed indexed units | `recent_changes` | git diff/history |
39
+ | Discover architectural domains | `domain_clusters` | `graph_analysis` |
40
+ | Check a join or foreign key across databases before writing it | `graph_analysis` with `analysis: "cross_database_edges"` | `lookup` on both models |
41
+ | Find dependencies that change faster than their dependents | `graph_analysis` with `analysis: "volatile_dependencies"` | `recent_changes` |
42
+ | See a Packwerk boundary before calling across it | `graph_analysis` with `analysis: "undeclared_package_edges"` | `lookup` on the package unit |
43
+ | Find central or high-impact units | `pagerank` | `dependents` |
44
+ | Ask a conceptual question | `codebase_retrieve` if status says ready | `lookup` and graph tools |
45
+ | Refresh after a published extraction | `reload` | `woods_status` |
46
+
47
+ Do not start with a broad graph or semantic query when an exact search will answer the question with less noise.
48
+
49
+ ## Core workflows
50
+
51
+ ### Understand a model
52
+
53
+ 1. `search(query: "^Order$", types: ["model"])`
54
+ 2. `lookup(identifier: <returned identifier>)`
55
+ 3. Read resolved schema, associations, validations, scopes, enums, callbacks, and included concerns.
56
+ 4. `dependencies(identifier: ..., depth: 1)` for collaborators.
57
+ 5. `dependents(identifier: ..., depth: 1)` for callers and affected features.
58
+
59
+ Woods may inline concern behavior beside the owning model. Distinguish the resolved runtime view from the physical file that originally defined a method.
60
+
61
+ ### Trace a feature flow
62
+
63
+ 1. Search for the route, controller action, job, mailer, or service at the user-visible entry point.
64
+ 2. Call `trace_flow` on the exact identifier.
65
+ 3. Inspect important or ambiguous nodes with `lookup`.
66
+ 4. Follow missing branches with `dependencies` and a narrow `via` filter when useful.
67
+ 5. Verify behavior that depends on conditions, dynamic dispatch, or runtime data in source and tests.
68
+
69
+ ### Assess change impact
70
+
71
+ 1. Search and look up the unit being changed.
72
+ 2. Call `dependents` at depth 1 before increasing depth.
73
+ 3. Group results by relationship type and application layer.
74
+ 4. Trace the most relevant user-facing or asynchronous flows.
75
+ 5. Use test mappings and repository search to select tests; do not equate a graph edge with test coverage.
76
+
77
+ Report direct dependents separately from inferred downstream impact.
78
+
79
+ ### Diagnose missing context
80
+
81
+ If an expected unit is absent:
82
+
83
+ 1. Check `woods_status` and generation time.
84
+ 2. Search by a broader literal prefix or suffix.
85
+ 3. Search relevant source or metadata fields.
86
+ 4. Confirm the extractor supports that unit type in [Extractor reference](EXTRACTOR_REFERENCE.md).
87
+ 5. Ask for `woods:incremental` or a full `woods:extract` when the index predates the code.
88
+
89
+ “Not found in this generation” is evidence about the index, not proof that the code does not exist.
90
+
91
+ ## Search precisely
92
+
93
+ `search` accepts a Ruby regular expression in `query`. It also supports literal `exact_prefix` and `exact_suffix`, which are safer for namespaced identifiers.
94
+
95
+ Good patterns:
96
+
97
+ ```text
98
+ query: "Order|Purchase", types: ["model", "service"]
99
+ exact_prefix: "Admin::Billing::"
100
+ exact_suffix: "Controller"
101
+ fields: ["identifier", "source_code", "metadata"]
102
+ ```
103
+
104
+ Start with identifier search. Add source or metadata only when name discovery fails. Restrict types and keep result limits small enough to inspect.
105
+
106
+ ## Traverse deliberately
107
+
108
+ `dependencies` means “what this unit uses.” `dependents` means “what uses this unit.” Both default to bounded breadth-first traversal and accept type or relationship filters.
109
+
110
+ Start at depth 1 or 2. A deeper unfiltered traversal can obscure the direct evidence that matters. Common relationship values include associations (`belongs_to`, `has_many`, `has_one`), code references, renders, redirects, form actions, and navigation links.
111
+
112
+ Both return at most 50 nodes and say so with a `Showing N of M (truncated)`
113
+ line. Narrow with `depth`, `types` and `via` before paging with `limit` and
114
+ `offset`: narrowing answers the question, paging only splits the same answer
115
+ across turns. In a multi-database app each row names the unit's database.
116
+
117
+ Use returned relationship labels as evidence. Do not infer call order from a dependency edge alone.
118
+
119
+ ## Use semantic retrieval only when ready
120
+
121
+ `codebase_retrieve` answers natural-language questions with token-budgeted context. Use it when `woods_status` reports a configured embedding provider and current vector data.
122
+
123
+ Important parameters:
124
+
125
+ - `query`: the conceptual question;
126
+ - `budget`: token budget, default 8,000;
127
+ - `types`: restrict results and opt specific types in;
128
+ - `exclude_types`: remove noisy types.
129
+
130
+ Do not pass `limit`; retrieval is governed by `budget`. Test mappings are excluded by default so filenames do not dominate semantic rank. After retrieval, verify key units with `lookup` rather than treating ranked context as exhaustive.
131
+
132
+ If retrieval is disabled, use `search`, `lookup`, and graph tools. Do not request credentials or reconfigure the project without authorization.
133
+
134
+ ## Index Server boundaries
135
+
136
+ The normal packaged server registers 14 tools:
137
+
138
+ `woods_status`, `search`, `lookup`, `dependencies`, `dependents`, `structure`, `trace_flow`, `framework`, `recent_changes`, `graph_analysis`, `domain_clusters`, `pagerank`, `reload`, and `codebase_retrieve`.
139
+
140
+ Source inventory contains conditional tools for sessions, pipeline operation, feedback, snapshots, and Notion. Do not call or promise them unless they appear in the connected server's tool list and their backing collaborator is configured.
141
+
142
+ ## Console Server boundaries
143
+
144
+ Console MCP is live-data access, not another code-search mode. Use it only when the user has authorized that environment and question.
145
+
146
+ The default executable registers:
147
+
148
+ - health/schema: `console_status`, `console_schema`;
149
+ - bounded records: `console_find`, `console_recent`, `console_sample`;
150
+ - projections/counts: `console_pluck`, `console_count`, `console_aggregate`, `console_association_count`.
151
+
152
+ `console_sql` and `console_query` appear only when embedded read tools are explicitly enabled. Tier 2 and Tier 3 inventory schemas and `console_eval` are not callable in supported packaged modes.
153
+
154
+ Before every Console call:
155
+
156
+ 1. confirm the authorized environment;
157
+ 2. use the narrowest model, fields, filters, and limit;
158
+ 3. avoid retrieving sensitive columns when aggregates or counts answer the question;
159
+ 4. treat redaction and scanners as defense in depth, not permission;
160
+ 5. do not work around a block or validation error.
161
+
162
+ See [Console MCP setup](CONSOLE_MCP_SETUP.md) for the safety model.
163
+
164
+ ## Report evidence clearly
165
+
166
+ When answering from Woods:
167
+
168
+ - name the tools and exact identifiers used;
169
+ - distinguish direct Woods evidence from your inference;
170
+ - cite source paths returned by Woods when available;
171
+ - state the index generation or staleness caveat when relevant;
172
+ - say when a conditional path still needs source or test verification;
173
+ - never claim the index is complete merely because a tool returned successfully.
174
+
175
+ A useful answer shape is:
176
+
177
+ ```text
178
+ Finding: <plain-language result>
179
+ Woods evidence: <tool + identifier + relationship/source>
180
+ Inference: <what follows from that evidence>
181
+ Verification: <source/test/history checked or still needed>
182
+ ```
183
+
184
+ ## Common mistakes
185
+
186
+ | Mistake | Better approach |
187
+ |---|---|
188
+ | Guessing an identifier | Discover it with `search` |
189
+ | Starting with semantic retrieval for an exact class | Use `search` then `lookup` |
190
+ | Treating no result as proof of absence | Check status, generation, extractor coverage, and source |
191
+ | Traversing deeply from the start | Begin at depth 1 or 2 and filter |
192
+ | Calling inventory-only tools | Use the connected server's registered list |
193
+ | Using Console for code structure | Use Index tools |
194
+ | Asking for `limit` on retrieval | Use `budget` |
195
+ | Trusting graph edges as execution order | Verify conditions and order in source/tests |
196
+ | Changing MCP or credentials while answering | Report the missing capability and ask the owner |
197
+
198
+ ## Related documentation
199
+
200
+ - [MCP servers](MCP_SERVERS.md): installation, client configuration, and exact surfaces.
201
+ - [MCP tool cookbook](MCP_TOOL_COOKBOOK.md): detailed parameters and response examples.
202
+ - [Extractor reference](EXTRACTOR_REFERENCE.md): indexed unit and edge contracts.
203
+ - [Retrieval guide](RETRIEVAL_GUIDE.md): embeddings, ranking, and token budgets.
204
+ - [Troubleshooting](TROUBLESHOOTING.md): stale indexes, disabled retrieval, and startup failures.
@@ -0,0 +1,205 @@
1
+ # Agent setup runbook
2
+
3
+ Use this runbook when a coding agent installs or configures Woods 2.0 in an existing Rails repository. The goal is a small, reviewable change and a working structural Index Server. Semantic retrieval and live-data access are separate opt-ins.
4
+
5
+ ## Default decision
6
+
7
+ Install the structural index only unless the user explicitly asks for another capability.
8
+
9
+ | Capability | Default | Requires explicit approval when agent-operated |
10
+ |---|---:|---|
11
+ | Extract Rails code and schema structure | On | No |
12
+ | Local or hosted embeddings | Off | Yes: adds a service, credentials, cost, or generated vectors |
13
+ | Console MCP | Off | Yes: boots Rails and can read live application data |
14
+ | HTTP MCP transport | Off | Yes: expands network exposure |
15
+ | Purging or rebuilding durable stores | Off | Yes: can remove Woods-owned data |
16
+
17
+ ## 1. Preflight without changing files
18
+
19
+ Read the repository's agent instructions first. Then record:
20
+
21
+ ```bash
22
+ git status --short --branch
23
+ ruby --version
24
+ bundle exec rails --version
25
+ bundle exec rails runner 'puts Rails.application.class.name'
26
+ ```
27
+
28
+ Also determine:
29
+
30
+ - whether Rails commands run on the host or through Docker Compose;
31
+ - which Compose service owns the Rails process, if applicable;
32
+ - the database adapter and whether migrations are allowed in this environment;
33
+ - whether `woods` already appears in the Gemfile or lockfile;
34
+ - whether `config/initializers/woods.rb`, Woods migrations, or Woods tables already exist;
35
+ - whether `tmp/woods/` is ignored or intentionally published.
36
+
37
+ If the worktree contains unrelated changes, preserve them. Do not overwrite an existing initializer or migration without showing the conflict to the user.
38
+
39
+ ## 2. Choose the installation path
40
+
41
+ Use structural-only setup when the user wants code navigation, runtime Rails structure, dependencies, flows, or blast-radius analysis. Fourteen tools register in the normal packaged launch without an embedding provider.
42
+
43
+ Discuss semantic retrieval only if the user needs natural-language `codebase_retrieve`. The choice depends on whether they prefer local Ollama or hosted OpenAI and which vector store fits their environment. See [Backend matrix](BACKEND_MATRIX.md).
44
+
45
+ Do not infer permission to configure Console MCP from a request to “set up Woods” or “set up MCP.” The Index Server reads generated code context; the Console Server can read live data.
46
+
47
+ ## 3. Install on a branch
48
+
49
+ Create or switch to the branch requested by the repository owner. Add only the development dependency:
50
+
51
+ ```ruby
52
+ # Gemfile
53
+ group :development do
54
+ gem "woods", "~> 2.0"
55
+ end
56
+ ```
57
+
58
+ Run the repository's normal dependency command:
59
+
60
+ ```bash
61
+ bundle install
62
+ bundle exec ruby -rwoods/version -e 'puts Woods::VERSION'
63
+ ```
64
+
65
+ Do not broadly update unrelated gems. Review the Gemfile and lockfile diff before continuing.
66
+
67
+ ## 4. Generate and inspect
68
+
69
+ ```bash
70
+ bin/rails generate woods:install
71
+ git diff -- config/initializers/woods.rb db/migrate
72
+ ```
73
+
74
+ The generator emits a legacy application migration for:
75
+
76
+ - `woods_units`
77
+ - `woods_edges`
78
+ - `woods_embeddings`
79
+
80
+ Woods 2's shipped structural index and storage backends do not use those application tables. For a new default installation, propose removing the generated migration from the working tree and get approval before doing so. Keep or run it only when repository history shows an older/custom integration uses the tables; confirm name conflicts and obtain explicit migration authorization first.
81
+
82
+ Follow repository policy for generated files and schema changes. Never run a production migration as an incidental setup step.
83
+
84
+ ## 5. Extract and validate
85
+
86
+ Use the same execution environment and boot variables the Rails app normally needs:
87
+
88
+ ```bash
89
+ bin/rails woods:extract
90
+ bin/rails woods:validate
91
+ bin/rails woods:stats
92
+ ```
93
+
94
+ If extraction fails, reproduce Rails boot and eager loading outside Woods before changing configuration:
95
+
96
+ ```bash
97
+ bin/rails runner 'puts Rails.application.class.name'
98
+ bin/rails runner 'Rails.application.eager_load!; puts "eager load ok"'
99
+ ```
100
+
101
+ Fix one root cause at a time. Do not suppress an application boot error to make extraction appear successful.
102
+
103
+ ## 6. Configure the Index MCP client
104
+
105
+ Prefer a project-scoped configuration so the executable, bundle, and index all belong to the same repository:
106
+
107
+ ```json
108
+ {
109
+ "mcpServers": {
110
+ "woods": {
111
+ "command": "bundle",
112
+ "args": ["exec", "woods-mcp-start", "./tmp/woods"],
113
+ "cwd": "/absolute/path/to/the-rails-app"
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ For Docker, extraction runs inside the Rails container. If Woods is installed only there, configure the client to launch `docker compose exec -T app bundle exec woods-mcp /app/tmp/woods` with the host application root as `cwd`. Use a host-side `bundle exec woods-mcp-start` only after verifying the host has a supported Ruby, the application bundle, and a host-visible index. In either mode, supply the path visible to the server process.
120
+
121
+ Reconnect the client and call `woods_status`. Confirm a current generation and non-zero unit counts before claiming setup works.
122
+
123
+ ## 7. Verify useful behavior
124
+
125
+ Use a class known to exist in the application:
126
+
127
+ 1. Call `search` to obtain its exact identifier.
128
+ 2. Call `lookup` to confirm source and metadata are present.
129
+ 3. Call `dependents` with depth 1 or 2 to confirm graph edges are queryable.
130
+
131
+ If `codebase_retrieve` reports that semantic search is disabled, that is expected for structural-only setup. Do not configure credentials merely to remove the message.
132
+
133
+ ## 8. Offer automatic index maintenance
134
+
135
+ Ask whether the owner wants Woods added to the development process manager. If authorized, use the repository's existing Procfile or equivalent convention:
136
+
137
+ ```text
138
+ web: bin/rails server
139
+ woods: bundle exec rake woods:watch
140
+ ```
141
+
142
+ The watcher catches up missed changes, maintains the structural index as files change, and publishes generations the Index MCP server detects automatically. Ordinary edits then need no manual re-extraction or MCP restart. It should run in development, not production.
143
+
144
+ Report these boundaries in the handoff:
145
+
146
+ - boot-captured changes make the watcher exit 75 and require supervisor restart;
147
+ - container bind mounts may require `WOODS_WATCH_POLL=1`;
148
+ - semantic vectors still require `woods:embed_incremental`;
149
+ - without a resident watcher, the fallback is `woods:incremental` after changes.
150
+
151
+ ## Stop and ask before
152
+
153
+ Get explicit user approval before:
154
+
155
+ - enabling Console MCP or granting access to a live database;
156
+ - enabling `console_embedded_read_tools`, `console_sql`, or `console_query`;
157
+ - adding an API key, hosted embedding provider, Qdrant, pgvector, or Ollama service;
158
+ - exposing MCP over HTTP, selecting bind addresses, or configuring bearer tokens;
159
+ - overriding a purge guard or deleting/rebuilding Woods durable data;
160
+ - overwriting an existing Woods initializer, migration, or MCP configuration;
161
+ - changing production or shared infrastructure.
162
+
163
+ ## Handoff report
164
+
165
+ Return a concise report the owner can verify:
166
+
167
+ ```text
168
+ Woods version:
169
+ Branch:
170
+
171
+ Files changed:
172
+ - Gemfile / lockfile:
173
+ - initializer:
174
+ - migration/schema:
175
+ - MCP client configuration:
176
+
177
+ Commands run:
178
+ - install:
179
+ - migrate:
180
+ - extract:
181
+ - validate/stats:
182
+
183
+ Verified capabilities:
184
+ - Index Server connected: yes/no
185
+ - woods_status current: yes/no
186
+ - search/lookup/dependents checked: yes/no
187
+ - semantic retrieval: disabled/enabled (provider)
188
+ - Console MCP: disabled/enabled (authorization)
189
+ - automatic structural updates: disabled/enabled (process manager)
190
+
191
+ Follow-up or unresolved risk:
192
+ ```
193
+
194
+ Never report a capability as enabled solely because its schema exists in source. Report what the packaged executable actually registered and what you called successfully.
195
+
196
+ ## Copyable prompt for an installation agent
197
+
198
+ > Install Woods 2.x in this Rails repository using `docs/AGENT_SETUP.md`. Start with read-only preflight and preserve unrelated changes. Default to the structural Index Server; do not enable embeddings, Console MCP, HTTP transport, secrets, or purge overrides without asking me. Inspect generated files before migrating, run extraction and validation in the app's normal execution environment, configure a project-scoped MCP server in the same filesystem context as the application bundle and index, and verify `woods_status`, `search`, `lookup`, and `dependents`. Finish with the runbook's handoff report.
199
+
200
+ ## Related guides
201
+
202
+ - [Getting started](GETTING_STARTED.md) for the human walkthrough.
203
+ - [MCP servers](MCP_SERVERS.md) for client-specific configuration and server boundaries.
204
+ - [Upgrade to Woods 2.0](UPGRADING_TO_2.md) for an existing 1.x installation.
205
+ - [Troubleshooting](TROUBLESHOOTING.md) for extraction and connection failures.