woods 2.0.0.beta2 → 2.0.0.beta3
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +262 -1
- data/CONTRIBUTING.md +173 -9
- data/README.md +7 -3
- data/SECURITY.md +9 -6
- data/docs/AGENT_GUIDE.md +83 -4
- data/docs/AGENT_SETUP.md +82 -1
- data/docs/BACKEND_MATRIX.md +20 -0
- data/docs/CLIENT_HOOKS.md +111 -0
- data/docs/CONFIGURATION_REFERENCE.md +199 -14
- data/docs/CONSOLE_MCP_SETUP.md +35 -5
- data/docs/DOCKER_SETUP.md +21 -2
- data/docs/EVALUATION.md +464 -1
- data/docs/EXTRACTOR_REFERENCE.md +36 -5
- data/docs/FAQ.md +11 -12
- data/docs/GETTING_STARTED.md +17 -5
- data/docs/INCREMENTAL_EXTRACTION.md +117 -1
- data/docs/INDEX_LAYOUT.md +382 -0
- data/docs/INTERNALS.md +7 -2
- data/docs/MCP_SERVERS.md +221 -5
- data/docs/MCP_TOOL_COOKBOOK.md +33 -18
- data/docs/NOTION_INTEGRATION.md +13 -0
- data/docs/OBSIDIAN_INTEGRATION.md +57 -9
- data/docs/PUBLISHED_INDEX.md +55 -0
- data/docs/README.md +7 -0
- data/docs/RETRIEVAL_GUIDE.md +253 -11
- data/docs/RUNTIME_TRACING.md +71 -0
- data/docs/SOURCE_FRESHNESS.md +143 -0
- data/docs/TROUBLESHOOTING.md +117 -5
- data/docs/UNBLOCKED_INTEGRATION.md +25 -0
- data/docs/UPGRADING_TO_2.md +44 -22
- data/docs/WATCH_DAEMON.md +259 -59
- data/exe/woods-agent-config +6 -0
- data/exe/woods-extract +5 -0
- data/exe/woods-hook-context +6 -0
- data/lib/generators/woods/templates/woods.rb.tt +1 -3
- data/lib/tasks/woods.rake +47 -397
- data/lib/woods/agent_configuration/applier.rb +133 -0
- data/lib/woods/agent_configuration/cli.rb +101 -0
- data/lib/woods/agent_configuration/cli_options.rb +29 -0
- data/lib/woods/agent_configuration/document.rb +105 -0
- data/lib/woods/agent_configuration/error.rb +7 -0
- data/lib/woods/agent_configuration/launcher.rb +75 -0
- data/lib/woods/agent_configuration/layout.rb +59 -0
- data/lib/woods/agent_configuration/managed_section.rb +62 -0
- data/lib/woods/agent_configuration/plan.rb +98 -0
- data/lib/woods/agent_configuration/plan_diff.rb +38 -0
- data/lib/woods/agent_configuration/planned_files.rb +61 -0
- data/lib/woods/agent_configuration/planner.rb +63 -0
- data/lib/woods/agent_configuration/planner_validation.rb +77 -0
- data/lib/woods/agent_configuration/preflight.rb +100 -0
- data/lib/woods/agent_configuration/recovery.rb +49 -0
- data/lib/woods/ast/node.rb +2 -0
- data/lib/woods/ast/parser.rb +38 -5
- data/lib/woods/builder.rb +21 -5
- data/lib/woods/cache/cache_middleware.rb +28 -7
- data/lib/woods/cache/cache_store.rb +4 -5
- data/lib/woods/change_set.rb +5 -4
- data/lib/woods/console/credential_index.rb +20 -2
- data/lib/woods/console/credential_scanner.rb +14 -14
- data/lib/woods/console/credential_scanner_registry.rb +36 -0
- data/lib/woods/console/embedded_executor.rb +1 -1
- data/lib/woods/console/encrypted_credential_snapshot.rb +16 -0
- data/lib/woods/console/rack_middleware.rb +22 -13
- data/lib/woods/console/server.rb +18 -16
- data/lib/woods/dependency_graph.rb +65 -13
- data/lib/woods/embedding/corpus.rb +94 -0
- data/lib/woods/embedding/indexer.rb +90 -46
- data/lib/woods/embedding/openai.rb +17 -6
- data/lib/woods/evaluation/ablation_executor.rb +6 -1
- data/lib/woods/evaluation/ablation_timed_executor.rb +22 -4
- data/lib/woods/export/typed_reader.rb +56 -0
- data/lib/woods/extractor.rb +232 -137
- data/lib/woods/extractors/action_cable_extractor.rb +3 -1
- data/lib/woods/extractors/behavioral_profile.rb +9 -7
- data/lib/woods/extractors/caching_extractor.rb +3 -1
- data/lib/woods/extractors/concern_extractor.rb +64 -6
- data/lib/woods/extractors/configuration_extractor.rb +7 -3
- data/lib/woods/extractors/controller_extractor.rb +13 -4
- data/lib/woods/extractors/database_view_extractor.rb +3 -1
- data/lib/woods/extractors/decorator_extractor.rb +3 -1
- data/lib/woods/extractors/engine_extractor.rb +3 -1
- data/lib/woods/extractors/event_extractor.rb +4 -2
- data/lib/woods/extractors/factory_extractor.rb +3 -1
- data/lib/woods/extractors/graphql_extractor.rb +8 -2
- data/lib/woods/extractors/i18n_extractor.rb +3 -1
- data/lib/woods/extractors/job_extractor.rb +6 -19
- data/lib/woods/extractors/lib_extractor.rb +3 -1
- data/lib/woods/extractors/mailer_extractor.rb +20 -5
- data/lib/woods/extractors/manager_extractor.rb +3 -1
- data/lib/woods/extractors/method_parameters.rb +53 -0
- data/lib/woods/extractors/middleware_argument.rb +65 -0
- data/lib/woods/extractors/middleware_extractor.rb +9 -3
- data/lib/woods/extractors/migration_extractor.rb +3 -1
- data/lib/woods/extractors/model_extractor.rb +39 -33
- data/lib/woods/extractors/package_extractor.rb +24 -4
- data/lib/woods/extractors/phlex_extractor.rb +3 -1
- data/lib/woods/extractors/policy_extractor.rb +3 -1
- data/lib/woods/extractors/poro_extractor.rb +3 -1
- data/lib/woods/extractors/pundit_extractor.rb +3 -1
- data/lib/woods/extractors/rails_source_extractor.rb +4 -2
- data/lib/woods/extractors/rake_task_extractor.rb +4 -2
- data/lib/woods/extractors/route_extractor.rb +3 -1
- data/lib/woods/extractors/route_helper_resolver.rb +10 -33
- data/lib/woods/extractors/scheduled_job_extractor.rb +41 -15
- data/lib/woods/extractors/serializer_extractor.rb +4 -2
- data/lib/woods/extractors/service_extractor.rb +3 -1
- data/lib/woods/extractors/shared_dependency_scanner.rb +2 -2
- data/lib/woods/extractors/shared_utility_methods.rb +27 -15
- data/lib/woods/extractors/source_nesting.rb +1 -1
- data/lib/woods/extractors/state_machine_extractor.rb +3 -1
- data/lib/woods/extractors/test_mapping_extractor.rb +3 -1
- data/lib/woods/extractors/validator_extractor.rb +3 -1
- data/lib/woods/extractors/view_component_extractor.rb +3 -1
- data/lib/woods/extractors/view_template_extractor.rb +3 -1
- data/lib/woods/gem_mapper.rb +2 -0
- data/lib/woods/git_history.rb +116 -0
- data/lib/woods/graph_analyzer.rb +35 -6
- data/lib/woods/hooks/context_cli.rb +54 -0
- data/lib/woods/hooks/context_event.rb +88 -0
- data/lib/woods/hooks/context_hint.rb +73 -0
- data/lib/woods/hooks/context_impact.rb +77 -0
- data/lib/woods/hooks/context_output.rb +47 -0
- data/lib/woods/hooks/context_state.rb +102 -0
- data/lib/woods/hooks/refresh.rb +79 -0
- data/lib/woods/hooks/rule_projection.rb +78 -0
- data/lib/woods/input_rules.rb +19 -0
- data/lib/woods/mcp/bearer_auth.rb +20 -12
- data/lib/woods/mcp/bootstrapper.rb +62 -0
- data/lib/woods/mcp/index_reader.rb +323 -160
- data/lib/woods/mcp/initialization_guidance.rb +27 -0
- data/lib/woods/mcp/origin_guard.rb +17 -9
- data/lib/woods/mcp/published_lexical_retriever.rb +115 -0
- data/lib/woods/mcp/renderers/markdown_renderer.rb +8 -1
- data/lib/woods/mcp/renderers/plain_renderer.rb +7 -1
- data/lib/woods/mcp/search_results.rb +74 -0
- data/lib/woods/mcp/server.rb +158 -37
- data/lib/woods/mcp/tool_contract.rb +2 -0
- data/lib/woods/mcp/tool_response_renderer.rb +25 -0
- data/lib/woods/mcp/traversal_evidence.rb +113 -0
- data/lib/woods/mcp/traversal_evidence_index.rb +100 -0
- data/lib/woods/mcp/traversal_evidence_page.rb +41 -0
- data/lib/woods/mcp/traversal_evidence_text.rb +52 -0
- data/lib/woods/notion/exporter.rb +56 -17
- data/lib/woods/obsidian/destination_plan.rb +98 -0
- data/lib/woods/obsidian/name_mapper.rb +19 -3
- data/lib/woods/obsidian/note_builder.rb +19 -10
- data/lib/woods/obsidian/vault_exporter.rb +88 -32
- data/lib/woods/operator/pipeline_guard.rb +18 -13
- data/lib/woods/path_dispatcher.rb +7 -1
- data/lib/woods/payload_store.rb +27 -26
- data/lib/woods/railtie.rb +3 -3
- data/lib/woods/railtie_support.rb +12 -12
- data/lib/woods/rake_helpers.rb +392 -0
- data/lib/woods/resilience/graph_invariant_validator/membership_checks.rb +71 -0
- data/lib/woods/resilience/graph_invariant_validator/node_checks.rb +61 -0
- data/lib/woods/resilience/graph_invariant_validator/reverse_relationship_checks.rb +46 -0
- data/lib/woods/resilience/graph_invariant_validator.rb +119 -0
- data/lib/woods/resilience/index_validator/graph_checks.rb +80 -0
- data/lib/woods/resilience/index_validator.rb +112 -23
- data/lib/woods/retrieval/context_assembler.rb +50 -15
- data/lib/woods/retrieval/lexical_assembler.rb +73 -0
- data/lib/woods/retrieval/lexical_index.rb +119 -0
- data/lib/woods/retrieval/ranker.rb +4 -2
- data/lib/woods/retrieval/scope.rb +108 -0
- data/lib/woods/retrieval/scoped_graph_store.rb +32 -0
- data/lib/woods/retrieval/scoped_vector_store.rb +55 -0
- data/lib/woods/retrieval/search_executor.rb +86 -27
- data/lib/woods/retrieval/source_evidence.rb +200 -0
- data/lib/woods/retriever.rb +98 -22
- data/lib/woods/ruby_analyzer/trace_enricher.rb +77 -38
- data/lib/woods/session_tracer/middleware.rb +10 -12
- data/lib/woods/session_tracer/redis_store.rb +22 -6
- data/lib/woods/session_tracer/session_flow_assembler.rb +23 -17
- data/lib/woods/session_tracer/solid_cache_coordination.rb +6 -4
- data/lib/woods/session_tracer/unit_resolver.rb +63 -0
- data/lib/woods/source_inputs/consumer_errors.rb +27 -0
- data/lib/woods/source_inputs/handoff.rb +102 -0
- data/lib/woods/source_inputs/launcher.rb +157 -0
- data/lib/woods/source_inputs/manifest.rb +124 -0
- data/lib/woods/source_inputs/private_key.rb +55 -0
- data/lib/woods/source_inputs/scanner.rb +171 -0
- data/lib/woods/source_inputs/scopes.rb +71 -0
- data/lib/woods/source_inputs/session.rb +214 -0
- data/lib/woods/source_inputs/status.rb +84 -0
- data/lib/woods/source_inputs/verifier.rb +107 -0
- data/lib/woods/storage/metadata_store.rb +25 -25
- data/lib/woods/storage/pgvector.rb +29 -8
- data/lib/woods/storage/qdrant.rb +17 -7
- data/lib/woods/storage/vector_store.rb +18 -6
- data/lib/woods/tasks.rb +3 -2
- data/lib/woods/temporal/json_snapshot_store.rb +29 -8
- data/lib/woods/unblocked/exporter.rb +59 -70
- data/lib/woods/version.rb +1 -1
- data/lib/woods/watch/boot_snapshot.rb +52 -0
- data/lib/woods/watch/daemon.rb +136 -28
- data/lib/woods/watch/listen_watcher.rb +4 -0
- data/lib/woods/watch/polling_watcher.rb +5 -1
- data/lib/woods/watch/status.rb +20 -15
- data/lib/woods/watch/tree_scan.rb +21 -13
- data/lib/woods/watch/watcher.rb +4 -1
- data/lib/woods.rb +50 -11
- data/plugin/.claude-plugin/plugin.json +1 -1
- data/plugin/hooks/adapters/normalize.jq +15 -0
- data/plugin/hooks/adapters/normalize.rb +63 -0
- data/plugin/hooks/hooks.json +20 -0
- data/plugin/hooks/woods-context.sh +50 -0
- data/plugin/hooks/woods-input-rules.sh +159 -0
- data/plugin/hooks/woods-opencode.mjs +65 -0
- data/plugin/hooks/woods-post-edit.sh +2 -225
- data/plugin/hooks/woods-refresh.sh +260 -0
- data/plugin/hooks/woods-session-start.sh +47 -55
- data/plugin/skills/woods-agent-enable/SKILL.md +13 -0
- data/plugin/skills/woods-diagnose/SKILL.md +288 -1
- data/plugin/skills/woods-investigate/SKILL.md +106 -0
- data/plugin/skills/woods-mcp-config/SKILL.md +89 -1
- data/plugin/skills/woods-setup/SKILL.md +107 -6
- metadata +84 -5
data/docs/AGENT_GUIDE.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
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
4
|
|
|
5
|
+
Supporting servers also send a concise version of this workflow in MCP
|
|
6
|
+
initialization/discovery instructions, without requiring an installed plugin.
|
|
7
|
+
Check the connected server's version and registered tools; this feature is
|
|
8
|
+
unreleased after `2.0.0.beta2`, and protocol `2024-11-05` omits the field.
|
|
9
|
+
The [initialization contract](MCP_SERVERS.md#initialization-guidance) describes
|
|
10
|
+
availability. This guide remains the detailed reference when instructions are
|
|
11
|
+
absent or the client does not display them.
|
|
12
|
+
|
|
5
13
|
## Start every session with status
|
|
6
14
|
|
|
7
15
|
Call `woods_status` before relying on the index. Check:
|
|
@@ -13,6 +21,11 @@ Call `woods_status` before relying on the index. Check:
|
|
|
13
21
|
|
|
14
22
|
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
23
|
|
|
24
|
+
Compare `index.woods_version` (last manifest publisher, unknown for older indexes)
|
|
25
|
+
with `server.version` (the MCP reader). A major-version difference warrants a
|
|
26
|
+
full extraction and upgrade review; a match does not prove every retained unit
|
|
27
|
+
was rewritten. See [manifest writer provenance](PUBLISHED_INDEX.md#manifest-writer-provenance).
|
|
28
|
+
|
|
16
29
|
## The default query loop
|
|
17
30
|
|
|
18
31
|
Use this four-step loop for most codebase questions:
|
|
@@ -103,22 +116,48 @@ fields: ["identifier", "source_code", "metadata"]
|
|
|
103
116
|
|
|
104
117
|
Start with identifier search. Add source or metadata only when name discovery fails. Restrict types and keep result limits small enough to inspect.
|
|
105
118
|
|
|
119
|
+
On supporting versions, read `completeness` before calling search exhaustive.
|
|
120
|
+
`result_count` counts returned rows. `result_limit` proves one more match exists;
|
|
121
|
+
`scan_budget` and `regex_timeout` leave that unknown. Only `exhausted` establishes
|
|
122
|
+
an exact total within the requested index/query domain. Narrow types, literal
|
|
123
|
+
prefix/suffix filters, or deep fields when `partial` is true. A detected artifact
|
|
124
|
+
failure remains an error with unknown completeness, never proof of no matches.
|
|
125
|
+
|
|
126
|
+
This metadata is unreleased after `2.0.0.beta2`; older servers may omit it.
|
|
127
|
+
Do not infer completeness from a full page or missing metadata. See the
|
|
128
|
+
[search response contract](MCP_SERVERS.md#search-completeness).
|
|
129
|
+
|
|
106
130
|
## Traverse deliberately
|
|
107
131
|
|
|
108
132
|
`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
133
|
|
|
110
134
|
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
135
|
|
|
112
|
-
Both return at most 50 nodes and say so with a `Showing N of M (truncated)`
|
|
136
|
+
Both return at most 50 nodes by default and say so with a `Showing N of M (truncated)`
|
|
113
137
|
line. Narrow with `depth`, `types` and `via` before paging with `limit` and
|
|
114
138
|
`offset`: narrowing answers the question, paging only splits the same answer
|
|
115
139
|
across turns. In a multi-database app each row names the unit's database.
|
|
116
140
|
|
|
117
|
-
|
|
141
|
+
A traversal can also stop at its independent node or edge budget. Treat
|
|
142
|
+
`partial`/`partial_reason` as incomplete graph evidence even on the final page;
|
|
143
|
+
paging cannot recover nodes the walk never reached. Check the connected schema
|
|
144
|
+
before using `max_nodes`/`max_edges`, and follow the
|
|
145
|
+
[budget contract](MCP_SERVERS.md#dependency-traversal-budgets).
|
|
118
146
|
|
|
119
|
-
|
|
147
|
+
When the connected schema supports `explain`, request `explain: true` to see
|
|
148
|
+
recorded source-to-target relationships and a shared shortest witness to each
|
|
149
|
+
row. Report `direct` relationships separately from `transitive` inferred impact.
|
|
150
|
+
Follow `parent`/`edge_id` references; `context: true` ancestors are outside the
|
|
151
|
+
current result page. Unknown labels and ambiguous candidate types stay unknown;
|
|
152
|
+
`typed_path_complete: false` does not establish a uniquely typed path. See the
|
|
153
|
+
[explanation contract](MCP_SERVERS.md#traversal-explanations).
|
|
120
154
|
|
|
121
|
-
|
|
155
|
+
Use recorded relationship labels as evidence. Do not infer execution or call
|
|
156
|
+
order from a dependency edge alone.
|
|
157
|
+
|
|
158
|
+
## Use ranked retrieval only when ready
|
|
159
|
+
|
|
160
|
+
`codebase_retrieve` answers natural-language questions with token-budgeted context. Use it when `woods_status` reports explicit lexical mode over a current published index, or a configured embedding provider and current vector data in semantic mode. Lexical mode explains matching terms/fields and does not infer synonyms absent from the text; a no-match response is not proof of missing behavior.
|
|
122
161
|
|
|
123
162
|
Important parameters:
|
|
124
163
|
|
|
@@ -202,3 +241,43 @@ Verification: <source/test/history checked or still needed>
|
|
|
202
241
|
- [Extractor reference](EXTRACTOR_REFERENCE.md): indexed unit and edge contracts.
|
|
203
242
|
- [Retrieval guide](RETRIEVAL_GUIDE.md): embeddings, ranking, and token budgets.
|
|
204
243
|
- [Troubleshooting](TROUBLESHOOTING.md): stale indexes, disabled retrieval, and startup failures.
|
|
244
|
+
|
|
245
|
+
### Explicit retrieval and discovery scope
|
|
246
|
+
|
|
247
|
+
On a server whose tool schema advertises them, `packages` and `source_paths` narrow
|
|
248
|
+
`search` and `codebase_retrieve` before candidate limits. These are per-call
|
|
249
|
+
arguments, not configuration settings. Inspect applied scope and completeness;
|
|
250
|
+
a narrow graph query can omit relevant cross-boundary dependencies. See the
|
|
251
|
+
[scope contract](RETRIEVAL_GUIDE.md#explicit-package-and-source-path-scopes) for
|
|
252
|
+
root/nested ownership, path normalization, errors, storage support, and cost.
|
|
253
|
+
|
|
254
|
+
### Verify source content before relying on freshness
|
|
255
|
+
|
|
256
|
+
When supported by the installed version, inspect `woods_status.index.source_freshness`.
|
|
257
|
+
Repeated edits can leave the porcelain fingerprint unchanged. A quick-budget
|
|
258
|
+
`unknown` can justify one explicit `source_check: "deep"` call; persistent unknown
|
|
259
|
+
needs the reported limitation resolved, not repeated status polling. Use
|
|
260
|
+
`bundle exec woods-extract full` to establish verified preboot source evidence.
|
|
261
|
+
A named refresh does not certify unrelated consumers or external runtime state.
|
|
262
|
+
Follow [source freshness](SOURCE_FRESHNESS.md) and keep ordinary query scopes narrow.
|
|
263
|
+
|
|
264
|
+
### Recovering relevant code under a small context budget
|
|
265
|
+
|
|
266
|
+
Check the installed schemas before requesting `evidence: 'compact'` on retrieval
|
|
267
|
+
or lookup, or `evidence: 'outline'` for API orientation. These modes preserve
|
|
268
|
+
complete selected spans and explicitly report omissions. An outline is not proof
|
|
269
|
+
of implementation behavior. Follow the returned typed `full_evidence` call when
|
|
270
|
+
you need full source; its SHA guard refuses changed source instead of validating
|
|
271
|
+
a different publication accidentally. Published-unit line/byte ranges can include
|
|
272
|
+
synthesized or commented concern source and are not physical file coordinates.
|
|
273
|
+
See the [evidence contract](RETRIEVAL_GUIDE.md#compact-published-evidence-and-api-outlines).
|
|
274
|
+
|
|
275
|
+
### Optional hook hints
|
|
276
|
+
|
|
277
|
+
When explicitly enabled on a supporting installed gem, Claude hook context offers
|
|
278
|
+
a small served-generation orientation and post-edit candidate dependents. Treat
|
|
279
|
+
pre-refresh, unknown freshness, truncation and ambiguous identity labels as limits
|
|
280
|
+
on the evidence. Verify direct and inferred downstream candidates using typed
|
|
281
|
+
lookup and `dependents explain:true`; suggested tests do not prove coverage.
|
|
282
|
+
Silence does not establish no impact. See [bounded context hints](WATCH_DAEMON.md#optional-bounded-context-hints)
|
|
283
|
+
for opt-in, independent refresh controls, limits and repeat suppression.
|
data/docs/AGENT_SETUP.md
CHANGED
|
@@ -46,7 +46,15 @@ Do not infer permission to configure Console MCP from a request to “set up Woo
|
|
|
46
46
|
|
|
47
47
|
## 3. Install on a branch
|
|
48
48
|
|
|
49
|
-
Create or switch to the branch requested by the repository owner.
|
|
49
|
+
Create or switch to the branch requested by the repository owner. Select the
|
|
50
|
+
published version using the [installation guide](GETTING_STARTED.md#1-install-the-gem).
|
|
51
|
+
Before stable 2.x is published, use the exact published prerelease constraint
|
|
52
|
+
from the README release table; `~> 2.0` will not select a beta or release candidate.
|
|
53
|
+
Use the selected version's tag documentation and verify its capabilities before
|
|
54
|
+
configuring features described on `main`.
|
|
55
|
+
|
|
56
|
+
Add only the development dependency. The following constraint applies **after a
|
|
57
|
+
stable 2.x release is published**:
|
|
50
58
|
|
|
51
59
|
```ruby
|
|
52
60
|
# Gemfile
|
|
@@ -120,6 +128,77 @@ For Docker, extraction runs inside the Rails container. If Woods is installed on
|
|
|
120
128
|
|
|
121
129
|
Reconnect the client and call `woods_status`. Confirm a current generation and non-zero unit counts before claiming setup works.
|
|
122
130
|
|
|
131
|
+
### Managed Claude Code configuration
|
|
132
|
+
|
|
133
|
+
The development command `woods-agent-config` is unreleased after 2.0.0.beta2.
|
|
134
|
+
Check `bundle exec woods-agent-config --help` in the selected application bundle;
|
|
135
|
+
use the manual client configuration below when it is absent. The supported
|
|
136
|
+
client format is Claude Code (tested with 2.1.267).
|
|
137
|
+
|
|
138
|
+
Create a private plan, inspect its paths and diff, then apply that same plan:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
bundle exec woods-agent-config setup --client claude --scope project \
|
|
142
|
+
--root "$PWD" --instructions CLAUDE.md,AGENTS.md --plan /tmp/woods-setup.json --diff
|
|
143
|
+
bundle exec woods-agent-config apply /tmp/woods-setup.json \
|
|
144
|
+
--client claude --scope project --root "$PWD"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Choose a new, unused plan filename for each preview. Preview writes only the
|
|
148
|
+
requested plan file; it does not edit managed configuration. Plans contain the
|
|
149
|
+
complete replacement bytes, including unrelated settings, and use mode 0600:
|
|
150
|
+
keep them private and remove them when no longer needed. `show FILE` prints its
|
|
151
|
+
summary; `show FILE --diff` checks the original snapshots and prints a unified
|
|
152
|
+
diff. Applying a changed snapshot fails rather than replacing the new content.
|
|
153
|
+
A repeated identical setup makes no configuration edits.
|
|
154
|
+
|
|
155
|
+
| Selection | Managed files |
|
|
156
|
+
|---|---|
|
|
157
|
+
| `--scope project` | `<root>/.mcp.json`, explicitly selected `<root>/CLAUDE.md` and/or `AGENTS.md`, `<root>/.woods-agent-config.json` ownership receipt |
|
|
158
|
+
| `--scope user` | `~/.claude.json`, explicitly selected `~/.claude/CLAUDE.md`, application-specific receipt in `~/.claude/` |
|
|
159
|
+
|
|
160
|
+
With `CLAUDE_CONFIG_DIR`, user scope uses that directory's `.claude.json`,
|
|
161
|
+
`CLAUDE.md`, and receipt instead. Instruction edits are opt-in with
|
|
162
|
+
`--instructions`; existing selections carry forward on update. The command
|
|
163
|
+
configures the Index Server. Client trust and project approval remain Claude
|
|
164
|
+
Code settings; apply does not change them.
|
|
165
|
+
|
|
166
|
+
Preflight runs the selected installed bundle, validates its index, and checks
|
|
167
|
+
its actual registered capabilities. It does not boot Rails or contact an
|
|
168
|
+
embedding provider. The bundle must already resolve in frozen mode; prepare
|
|
169
|
+
its lockfile separately if Bundler reports a mismatch. Host mode uses the
|
|
170
|
+
application's absolute Gemfile and index paths. `--index tmp/woods` is relative
|
|
171
|
+
to the selected root. For Compose, also select `--mode compose --service web
|
|
172
|
+
--container-root /app`; run the configuration command where Docker Compose can
|
|
173
|
+
access that project. Preflight verifies the index and installed gem inside that
|
|
174
|
+
service. Both host and container subprocesses have time limits.
|
|
175
|
+
|
|
176
|
+
Use `update --plan FILE` with the same client/scope/root and the desired launch
|
|
177
|
+
options to change the owned entry or instruction selection. Update explicitly
|
|
178
|
+
records the current template and installed-gem evidence; background hooks never
|
|
179
|
+
update configuration. `remove --plan FILE` previews deletion of owned content
|
|
180
|
+
and does not require the application bundle or index to remain available.
|
|
181
|
+
Use `--name NAME` consistently if the installation uses a nondefault server name.
|
|
182
|
+
Apply each operation's saved plan with the same explicit client/scope/root.
|
|
183
|
+
|
|
184
|
+
Ownership comes from the receipt and exact managed section, not from a server
|
|
185
|
+
named `woods`. Existing unowned names, edited managed content, malformed JSON,
|
|
186
|
+
duplicate markers, symlinks, and concurrent edits cause conflicts. Preserve the
|
|
187
|
+
receipt for future update/removal. Unrelated servers, hooks, settings,
|
|
188
|
+
instruction text, permissions, and line-ending conventions are retained;
|
|
189
|
+
changing JSON may reformat its whitespace.
|
|
190
|
+
|
|
191
|
+
Writes use atomic replacement per file and a private recovery journal beside
|
|
192
|
+
the receipt. The plan summary names the `.lock` and `.pending` runtime paths;
|
|
193
|
+
a lock file may remain after completion. Multiple files are not one atomic
|
|
194
|
+
transaction. An ordinary write failure restores original files when safe; an
|
|
195
|
+
interruption or concurrent edit can retain the journal. Resolve reported
|
|
196
|
+
conflicts, then use `recover --client claude --scope project --root "$PWD"`
|
|
197
|
+
(or the original user scope). Recovery refuses to overwrite concurrent edits.
|
|
198
|
+
Keep journals private because they contain original configuration bytes. A plan
|
|
199
|
+
whose recovery journal would exceed 8 MiB is refused before any managed file
|
|
200
|
+
is changed; reduce the selected configuration before applying.
|
|
201
|
+
|
|
123
202
|
## 7. Verify useful behavior
|
|
124
203
|
|
|
125
204
|
Use a class known to exist in the application:
|
|
@@ -199,6 +278,8 @@ Never report a capability as enabled solely because its schema exists in source.
|
|
|
199
278
|
|
|
200
279
|
## Related guides
|
|
201
280
|
|
|
281
|
+
- [Edit client adapters](CLIENT_HOOKS.md) for separately opt-in Claude/OpenCode edit hooks; MCP setup does not enable them.
|
|
282
|
+
|
|
202
283
|
- [Getting started](GETTING_STARTED.md) for the human walkthrough.
|
|
203
284
|
- [MCP servers](MCP_SERVERS.md) for client-specific configuration and server boundaries.
|
|
204
285
|
- [Upgrade to Woods 2.0](UPGRADING_TO_2.md) for an existing 1.x installation.
|
data/docs/BACKEND_MATRIX.md
CHANGED
|
@@ -271,6 +271,12 @@ contract tests; it does not represent semantic quality. Other values raise
|
|
|
271
271
|
|
|
272
272
|
`build_metadata_store` accepts `:in_memory` and `:sqlite`. Nothing else is implemented.
|
|
273
273
|
|
|
274
|
+
Both adapters search Boolean fields as the JSON words `true` and `false`,
|
|
275
|
+
with case-insensitive substring matching. Numeric values `1` and `0` remain
|
|
276
|
+
separate from Booleans. Strings are searched without JSON quotes; objects and
|
|
277
|
+
arrays use JSON text. Null or absent fields never match a field-scoped query.
|
|
278
|
+
Whole-record search (`fields: nil`) searches serialized JSON, including keys.
|
|
279
|
+
|
|
274
280
|
### SQLite
|
|
275
281
|
|
|
276
282
|
**Best for:** Local development, zero-dependency setups, testing, and every shipped preset except pure in-memory.
|
|
@@ -284,6 +290,11 @@ contract tests; it does not represent semantic quality. Other values raise
|
|
|
284
290
|
- Single writer at a time
|
|
285
291
|
- No network access
|
|
286
292
|
|
|
293
|
+
Metadata search uses literal, ASCII-case-insensitive substring matching. Selected
|
|
294
|
+
string fields include embedded NUL characters in the searchable text. With no
|
|
295
|
+
field selection, search operates on serialized JSON, where NUL is represented
|
|
296
|
+
as `\u0000`; a literal NUL query therefore does not match that escaped text.
|
|
297
|
+
|
|
287
298
|
### In-memory
|
|
288
299
|
|
|
289
300
|
**Best for:** Testing, evaluation, small codebases.
|
|
@@ -318,6 +329,15 @@ A recursive-CTE graph store (MySQL 8.0+ or PostgreSQL, storing edges in a table
|
|
|
318
329
|
|
|
319
330
|
Indexing can be triggered synchronously (rake task, inline) or from a background job. The pipeline itself is job-system-agnostic, it's synchronous Ruby, and the wrapper below is just scheduling and concurrency control. Use `Woods.extract!` for a full run; incremental runs need a changed-file list, so a job usually just shells out to `rake woods:incremental` (which computes that list from git) rather than calling `Woods.extract_changed!` directly.
|
|
320
331
|
|
|
332
|
+
Both Ruby helpers hold the same heartbeat-maintained extraction lock as the
|
|
333
|
+
tasks and watch daemon. `WOODS_LOCK_WAIT` controls the wait (600 seconds by
|
|
334
|
+
default); timeout raises `Woods::Coordination::LockError`. Failed generation
|
|
335
|
+
publication raises `Woods::ExtractionError`, allowing job retries instead of
|
|
336
|
+
reporting unpublished work as success. The low-level `Woods::Extractor` remains
|
|
337
|
+
an orchestration building block: callers using it directly own locking and
|
|
338
|
+
publication-failure handling. Do not wrap the public helpers in a second Woods
|
|
339
|
+
extraction lock.
|
|
340
|
+
|
|
321
341
|
### Sidekiq
|
|
322
342
|
|
|
323
343
|
```ruby
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Edit hooks for Claude Code and OpenCode
|
|
2
|
+
|
|
3
|
+
Edit hooks are optional. MCP reads and `woods:watch` work independently of them.
|
|
4
|
+
Check the installed gem exposes `woods:hook_refresh` before enabling these
|
|
5
|
+
unreleased adapters; updating the plugin does not update the application gem.
|
|
6
|
+
Start the client from the Rails application root, with an existing index.
|
|
7
|
+
|
|
8
|
+
## Supported client contracts
|
|
9
|
+
|
|
10
|
+
| Client | Verified version | Events covered |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Claude Code | 2.1.267 | Successful `PostToolUse` for `Write` and `Edit`, using `tool_input.file_path` |
|
|
13
|
+
| Claude legacy compatibility | Existing single-file `MultiEdit` shape | One `tool_input.file_path`; this is not multi-file patch support |
|
|
14
|
+
| OpenCode | 1.18.27 | `tool.execute.after` for `apply_patch`, `write`, and `edit` |
|
|
15
|
+
|
|
16
|
+
The OpenCode patch adapter reads the successful tool's `metadata.files` array.
|
|
17
|
+
It includes every add, update, delete and move; a move becomes deletion of the
|
|
18
|
+
old path plus addition of the new path. `write` uses `metadata.filepath` and
|
|
19
|
+
`metadata.exists`; `edit` uses `metadata.filediff.file`. Patch text, source bytes,
|
|
20
|
+
diagnostics, session identifiers and arbitrary shell commands are not parsed
|
|
21
|
+
or placed in the queue. Actual client captures and their provenance live under
|
|
22
|
+
`spec/fixtures/hooks/`; the exact metadata contract is pinned to
|
|
23
|
+
[OpenCode v1.18.27 source](https://github.com/anomalyco/opencode/tree/v1.18.27/packages/opencode/src/tool).
|
|
24
|
+
See the primary [Claude hook reference](https://code.claude.com/docs/en/hooks)
|
|
25
|
+
and [OpenCode plugin reference](https://opencode.ai/docs/plugins/).
|
|
26
|
+
|
|
27
|
+
Other clients and arbitrary mutation tools are unsupported. Unknown shapes for
|
|
28
|
+
registered edit tools produce a short diagnostic instead of claiming refresh.
|
|
29
|
+
Use the resident watcher or an explicit extraction for unsupported operations.
|
|
30
|
+
OpenCode session-start/context hooks are not provided by this edit adapter.
|
|
31
|
+
|
|
32
|
+
## Claude Code registration
|
|
33
|
+
|
|
34
|
+
The Woods Claude plugin registers `woods-post-edit.sh` through its existing
|
|
35
|
+
`hooks/hooks.json`. The wrapper selects the explicit Claude parser, then the
|
|
36
|
+
shared runner handles queueing and extraction. Do not install a second copy of
|
|
37
|
+
the same hook. Existing single-file `MultiEdit` compatibility remains registered.
|
|
38
|
+
|
|
39
|
+
Enable the existing environment settings in the process launching the client:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
export WOODS_HOOKS_ENABLED=1
|
|
43
|
+
# Optional; relative to the application root:
|
|
44
|
+
export WOODS_OUTPUT=tmp/woods
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`WOODS_HOOKS_DISABLED=1` always wins. Enablement does not authorize Console MCP,
|
|
48
|
+
provider calls, user configuration writes, or daemon lifecycle changes.
|
|
49
|
+
|
|
50
|
+
## OpenCode project registration
|
|
51
|
+
|
|
52
|
+
Keep the complete Woods `plugin/` directory at a stable path visible to the
|
|
53
|
+
client. The Claude marketplace registration does not install a native OpenCode
|
|
54
|
+
plugin. Create a project-local `.opencode/plugins/woods.js` containing this one
|
|
55
|
+
import, replacing the path with that stable plugin location:
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
export { default } from "/absolute/path/to/woods/plugin/hooks/woods-opencode.mjs";
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
OpenCode automatically loads project `.js` and `.ts` plugin files at startup.
|
|
62
|
+
Use the `.js` wrapper name above; copying a standalone `.mjs` file into the
|
|
63
|
+
autoload directory does not register it. The wrapper imports the complete
|
|
64
|
+
adapter and shared runner; copying only the shell entry point is insufficient.
|
|
65
|
+
Restart OpenCode after registration and set `WOODS_HOOKS_ENABLED=1` in its launch
|
|
66
|
+
environment. This setup does not require npm packages or a host Rails bundle.
|
|
67
|
+
|
|
68
|
+
The adapter uses OpenCode's `directory` as the application root and verifies
|
|
69
|
+
that it belongs to the supplied git `worktree`. A Rails application nested
|
|
70
|
+
inside a repository therefore uses its own index. Each affected path must stay
|
|
71
|
+
inside that application root. Linked worktrees keep separate queues and indexes.
|
|
72
|
+
|
|
73
|
+
## Queue, paths and recovery
|
|
74
|
+
|
|
75
|
+
Both adapters use the same extraction eligibility, queue, command prefix,
|
|
76
|
+
deadline, locks and active-daemon behavior described in
|
|
77
|
+
[watch hook operation](WATCH_DAEMON.md#hooks-for-agent-sessions).
|
|
78
|
+
`WOODS_HOOK_RAKE="docker compose exec -T app bundle exec rake"` runs extraction
|
|
79
|
+
inside the application container. The host needs Bash 3.2 or later, Unix tools,
|
|
80
|
+
and either jq or Ruby; OpenCode supplies its own JavaScript runtime.
|
|
81
|
+
|
|
82
|
+
The complete event is validated before queueing. Empty/NUL paths, traversal,
|
|
83
|
+
foreign-project paths and symlink path components are rejected. Deleted paths
|
|
84
|
+
need not exist; contained symlinks are deliberately unsupported too. Spaces,
|
|
85
|
+
commas, newlines and Unicode paths remain intact. Adapter input is limited to
|
|
86
|
+
1 MiB and 1,000 affected paths; the OpenCode handoff is additionally limited to
|
|
87
|
+
48 KiB. An unsupported oversized event requires explicit extraction or watch.
|
|
88
|
+
Raw input uses a private temporary file during validation so the shell cannot
|
|
89
|
+
silently remove bytes. The runner removes that file before publishing the
|
|
90
|
+
path-only queue record, and cleans it up on handled exits.
|
|
91
|
+
|
|
92
|
+
One immutable queue file holds a multi-file event. The owner batches up to
|
|
93
|
+
16 files, 1,000 paths and 48 KiB without splitting an event. Existing single-path
|
|
94
|
+
queue records remain readable. A successful task, including a confirmed no-op,
|
|
95
|
+
acknowledges the batch; failure, timeout or daemon exit 75 retains every path.
|
|
96
|
+
At-least-once delivery can repeat work after a crash or event replay.
|
|
97
|
+
|
|
98
|
+
The OpenCode callback hands the event to a detached runner, which owns its
|
|
99
|
+
existing deadline. Callback completion means handoff, not index publication.
|
|
100
|
+
Inspect `<output>/hook.log`, the pending queue and the published generation to
|
|
101
|
+
confirm refresh. Malformed input diagnostics omit the original tool payload.
|
|
102
|
+
For rollback, disable hooks before removing registration; preserve pending
|
|
103
|
+
multi-file records until a compatible runner has consumed them.
|
|
104
|
+
|
|
105
|
+
## Optional Claude context
|
|
106
|
+
|
|
107
|
+
Claude has a separate opt-in for bounded synchronous orientation and change-impact
|
|
108
|
+
reminders. It does not change either client’s refresh queue contract and is not
|
|
109
|
+
enabled by `WOODS_HOOKS_ENABLED`. Check the installed helper, timing, path-mapping
|
|
110
|
+
and uncertainty contract in [bounded context hints](WATCH_DAEMON.md#optional-bounded-context-hints).
|
|
111
|
+
OpenCode refresh support does not imply context delivery support.
|