woods 2.0.0.beta1 → 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 +400 -1
- data/CONTRIBUTING.md +224 -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 +233 -13
- 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 +158 -2
- data/docs/INDEX_LAYOUT.md +382 -0
- data/docs/INTERNALS.md +15 -7
- 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 +71 -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/atomic_file.rb +133 -3
- 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 +557 -228
- 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/flow_assembler.rb +87 -8
- data/lib/woods/flow_precomputer.rb +44 -7
- data/lib/woods/gem_mapper.rb +2 -0
- data/lib/woods/git_history.rb +116 -0
- data/lib/woods/graph_analyzer.rb +195 -63
- 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 +29 -15
- 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 +80 -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 +135 -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/CONTRIBUTING.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Contributing to Woods
|
|
2
2
|
|
|
3
3
|
<!-- release-state:contributing-intro -->
|
|
4
|
-
Woods welcomes bug fixes, extractor coverage, storage and retrieval improvements, MCP compatibility work, documentation, and focused performance changes. This guide covers the shared contribution contract. Coding agents working from a source checkout should also read the repository's [AGENTS.md](https://github.com/lost-in-the/woods/blob/v2.0.0.
|
|
4
|
+
Woods welcomes bug fixes, extractor coverage, storage and retrieval improvements, MCP compatibility work, documentation, and focused performance changes. This guide covers the shared contribution contract. Coding agents working from a source checkout should also read the repository's [AGENTS.md](https://github.com/lost-in-the/woods/blob/v2.0.0.beta3/AGENTS.md).
|
|
5
5
|
<!-- release-state:end -->
|
|
6
6
|
|
|
7
7
|
## Choose the right channel
|
|
@@ -25,6 +25,8 @@ bin/rake spec
|
|
|
25
25
|
bin/rubocop
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
`Gemfile.lock` is gitignored, so a fresh worktree (as opposed to a clone) needs it copied in from an existing checkout before running any `bin/*` command.
|
|
29
|
+
|
|
28
30
|
Create a branch from current `main`. Keep each pull request to one logical change and preserve unrelated formatting and refactors for separate work.
|
|
29
31
|
|
|
30
32
|
`main` is the development branch: it holds work for the next release and can run ahead of the latest published gem. Releases are cut from version tags by the guarded workflow in the [release section below](#release-flow); documentation matching a published gem lives on that release's tag.
|
|
@@ -44,7 +46,7 @@ Create a branch from current `main`. Keep each pull request to one logical chang
|
|
|
44
46
|
| `plugin/skills/` | Distributed Woods skills (setup/upgrade, MCP configuration, investigation, agent enablement, diagnosis) |
|
|
45
47
|
|
|
46
48
|
<!-- release-state:contributing-architecture -->
|
|
47
|
-
Read [CLAUDE.md](https://github.com/lost-in-the/woods/blob/v2.0.0.
|
|
49
|
+
Read [CLAUDE.md](https://github.com/lost-in-the/woods/blob/v2.0.0.beta3/CLAUDE.md) for architecture and implementation gotchas before changing runtime behavior.
|
|
48
50
|
<!-- release-state:end -->
|
|
49
51
|
|
|
50
52
|
### Agent orientation and static self-map
|
|
@@ -94,7 +96,25 @@ bin/rubocop
|
|
|
94
96
|
|
|
95
97
|
Before requesting review, run the full unit suite and style check unless the PR explains why one cannot run.
|
|
96
98
|
|
|
97
|
-
Coverage from the default process excludes opt-in Rails, installed-artifact, and live-backend lanes. Report their results separately; a low percentage for subprocess-driven tasks does not establish that they are untested. CI enforces
|
|
99
|
+
Coverage from the default process excludes opt-in Rails, installed-artifact, and live-backend lanes. Report their results separately; a low percentage for subprocess-driven tasks does not establish that they are untested. CI enforces a 90% aggregate line floor and measures branches, but does not enforce a branch floor. The line gate was calibrated against local and CI default-suite results on 2026-09-18; it does not establish per-file coverage or coverage across the opt-in lanes. Add behavior-based regressions and real optional-gem fixtures for changed extraction paths before proposing higher thresholds.
|
|
100
|
+
|
|
101
|
+
### Pending examples in CI
|
|
102
|
+
|
|
103
|
+
CI fails when a running example becomes unexpectedly pending, including `skip`,
|
|
104
|
+
`xit`, and pending metadata. `spec/support/pending_policy.rb` records the exact
|
|
105
|
+
file, full description, reason, and unavailable capability for each reviewed
|
|
106
|
+
exception. Current exceptions cover the two optional tiktoken benchmarks, one
|
|
107
|
+
optional Tokenizers example, two Ruby-before-3.2 regexp-timeout examples, one
|
|
108
|
+
procfs example, and three filesystem-permission examples when running as root.
|
|
109
|
+
The Linux CI unit jobs run the real procfs identity example as an unprivileged
|
|
110
|
+
user, so the procfs and root exceptions normally apply only to other environments.
|
|
111
|
+
Opt-in suites excluded by their documented environment gates are not pending
|
|
112
|
+
examples. Focused runs do not need to include every reviewed exception.
|
|
113
|
+
|
|
114
|
+
Adding a new skip requires review of both its exact entry and capability check;
|
|
115
|
+
matching an existing reason alone is insufficient. Local runs retain normal
|
|
116
|
+
RSpec pending behavior. Exercise the policy and matrix consistency checks with
|
|
117
|
+
`CI=true bin/rspec spec/ci`.
|
|
98
118
|
|
|
99
119
|
### Rails version matrix
|
|
100
120
|
|
|
@@ -111,6 +131,44 @@ WOODS_RUN_BOOTED_APP=1 BUNDLE_GEMFILE=gemfiles/rails_7.2.gemfile \
|
|
|
111
131
|
bin/rspec spec/integration/booted_extraction_spec.rb
|
|
112
132
|
```
|
|
113
133
|
|
|
134
|
+
The unit suite evaluates every hand-maintained Rails gemfile and checks its
|
|
135
|
+
Appraisal requirements, old-Rails compatibility pins, and CI matrix membership.
|
|
136
|
+
This detects configuration drift; it does not replace the booted rows.
|
|
137
|
+
|
|
138
|
+
### Exact runtime dependency floors
|
|
139
|
+
|
|
140
|
+
The separate `minimum-dependencies` CI job runs on Ruby 3.0 with Bundler 2.5.23:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
gem install bundler -v 2.5.23
|
|
144
|
+
ruby script/test-minimum-dependencies
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Run outside `bundle exec`. The harness builds and installs the candidate gem,
|
|
148
|
+
resolves `gemfiles/minimum_runtime.gemfile` independently of the development
|
|
149
|
+
bundle, and verifies every loaded Woods library comes from that installed gem.
|
|
150
|
+
All five direct runtime dependencies are pinned to their advertised gemspec
|
|
151
|
+
floors. Transitive dependencies are compatible solver selections, **not** a
|
|
152
|
+
claim that every transitive version is minimal. CI retains the full resolved
|
|
153
|
+
version/platform list, lockfile, candidate gem and SHA-256 under the
|
|
154
|
+
`minimum-runtime-dependencies` artifact; local output defaults to
|
|
155
|
+
`tmp/minimum-dependencies/`.
|
|
156
|
+
|
|
157
|
+
The probe exercises lexical retrieval and typed lookup over a synthetic published
|
|
158
|
+
index, MCP SDK dispatch, Prism parsing, and MessagePack snapshots. It also boots
|
|
159
|
+
an actual Rails 6.0.0 API-style app, loads Woods tasks, and checks the real Rails
|
|
160
|
+
middleware stack for disabled Console passthrough, authorized requests, missing
|
|
161
|
+
and incorrect token refusal, and forbidden origins. Static serving is explicitly
|
|
162
|
+
disabled: Rails 6.0.0's own Static middleware predates Ruby 3 keyword forwarding.
|
|
163
|
+
This is a bounded Woods runtime-floor contract, not evidence that arbitrary
|
|
164
|
+
Rails 6.0.0 applications boot on Ruby 3. The booted Rails matrix uses compatible
|
|
165
|
+
patch releases and covers full extraction; enabled database-backed Console and
|
|
166
|
+
optional storage/provider combinations remain in their separate lanes.
|
|
167
|
+
|
|
168
|
+
The exact-floor job is required by release CI validation. Changing a runtime
|
|
169
|
+
lower bound requires updating its explicit pin and retaining a successful
|
|
170
|
+
installed-artifact run, rather than silently advancing a pin to make CI pass.
|
|
171
|
+
|
|
114
172
|
When adding a Rails line, update `Appraisals`, the corresponding hand-maintained gemfile, and `.github/workflows/ci.yml`. For Rails below 7.1, copy an existing 6.x gemfile so its sqlite3 and concurrent-ruby compatibility pins are preserved.
|
|
115
173
|
|
|
116
174
|
### Live storage and SQL dialects
|
|
@@ -125,6 +183,36 @@ WOODS_RUN_LIVE_BACKENDS=1 BUNDLE_GEMFILE=gemfiles/live_backends.gemfile \
|
|
|
125
183
|
|
|
126
184
|
The lane expects reachable PostgreSQL/pgvector, MySQL, and Qdrant services. Configure endpoints with `WOODS_PG_URL`, `WOODS_MYSQL_URL`, and `WOODS_QDRANT_URL`. The Console contracts exercise blocked-table enforcement and legitimate SQL on both database dialects. New adapter behavior that depends on a real server belongs in this lane.
|
|
127
185
|
|
|
186
|
+
### Solid Cache session compatibility
|
|
187
|
+
|
|
188
|
+
The live-backend job runs `spec/integration/solid_cache_compatibility_spec.rb`
|
|
189
|
+
against SQLite, PostgreSQL, and MySQL. MySQL coverage asserts that the adapter
|
|
190
|
+
has no insert `RETURNING`, checks actual insert ownership (including same-value
|
|
191
|
+
conflicts), exercises concurrent ownership, expiry, conditional deletion, and
|
|
192
|
+
session clear/epoch recovery. A separate case strips only insert-result metadata
|
|
193
|
+
to exercise the older Rails read-back fallback against real MySQL rows.
|
|
194
|
+
|
|
195
|
+
Solid Cache coordination depends on private APIs. Before declaring a newly
|
|
196
|
+
resolved `solid_cache` version supported:
|
|
197
|
+
|
|
198
|
+
1. Record the exact Ruby, Active Record, Solid Cache, and database versions.
|
|
199
|
+
2. Run the complete compatibility file against disposable PostgreSQL and MySQL
|
|
200
|
+
databases, with `WOODS_RUN_LIVE_BACKENDS=1`,
|
|
201
|
+
`BUNDLE_GEMFILE=gemfiles/live_backends.gemfile`, `WOODS_PG_URL`, and
|
|
202
|
+
`WOODS_MYSQL_URL` set. The suite recreates `solid_cache_entries`; never point
|
|
203
|
+
it at an application cache database.
|
|
204
|
+
3. Require every example to pass, including SQLite local-cache bypass, TTL,
|
|
205
|
+
sharding, missing-private-API errors, and the MySQL ownership cases. Attach
|
|
206
|
+
the versions and results to the PR; a passing double-based unit suite is
|
|
207
|
+
insufficient.
|
|
208
|
+
|
|
209
|
+
The live gemfile resolves `solid_cache ~> 1.0`; this is a dependency selection
|
|
210
|
+
range, not evidence that every version in it has been tested. The baseline
|
|
211
|
+
validated for #228 is Ruby 4.0.6, Solid Cache 1.0.10, Active Record 8.1.3.1,
|
|
212
|
+
SQLite 3.53.2, PostgreSQL 16.15, and MySQL 26.7.0.
|
|
213
|
+
Accepted crash/eviction limits are documented in the
|
|
214
|
+
[configuration reference](docs/CONFIGURATION_REFERENCE.md#solid-cache-session-retention-and-compatibility).
|
|
215
|
+
|
|
128
216
|
## Keep public surfaces synchronized
|
|
129
217
|
|
|
130
218
|
A pull request is incomplete when behavior and user guidance disagree.
|
|
@@ -191,8 +279,29 @@ RubyGems treats any letter in a version as a prerelease, so a `~> 1.6` or `~> 2.
|
|
|
191
279
|
### During feature work
|
|
192
280
|
|
|
193
281
|
- Do not edit `lib/woods/version.rb` by hand.
|
|
194
|
-
- Put changelog entries under `## [Unreleased]` only, beneath one of its `###` headings. Duplicate headings are merged at release time, in the order they first appear.
|
|
195
282
|
- Leave the `release-state` fences alone. `release:prepare` rewrites them.
|
|
283
|
+
- Put changelog entries under `## [Unreleased]`, beneath one of its `###` headings, or in an optional `changelog/<type>_<slug>.md` file. Entry files avoid conflicts between parallel branches; inline entries remain supported. Duplicate headings merge at release time, in the order they first appear.
|
|
284
|
+
|
|
285
|
+
Entry files contain nonempty UTF-8 Markdown without ATX (`#`) or setext
|
|
286
|
+
(underlined) headings, usually a bullet
|
|
287
|
+
and indented continuation lines. For example, `changelog/fixed_watch-restart.md`
|
|
288
|
+
can contain `- Preserve pending work across watch restarts.` Supported types are
|
|
289
|
+
`added`, `build`, `changed`, `dependencies`, `documentation`, `fixed`,
|
|
290
|
+
`performance`, `security`, `testing`, and `upgrade-notes`. Slugs start with a
|
|
291
|
+
lowercase letter or digit and use lowercase letters, digits, hyphens, or
|
|
292
|
+
underscores. Use one unique file per change; do not copy its entry into
|
|
293
|
+
Unreleased as well. Keep entry files directly inside a real `changelog/`
|
|
294
|
+
directory; symlinks and directories masquerading as entries are refused.
|
|
295
|
+
Other file extensions are left untouched.
|
|
296
|
+
|
|
297
|
+
`release:prepare` appends entry files in filename order after inline Unreleased
|
|
298
|
+
entries, folds them through the same heading merger, and deletes exactly the
|
|
299
|
+
consumed files. It validates every entry and documentation rewrite before
|
|
300
|
+
changing any files; an invalid entry or a later refusal preserves all entries.
|
|
301
|
+
A prepared release has an empty Unreleased section and no entry files. During
|
|
302
|
+
an ordinary beta cycle, entry files may accumulate even with an empty Unreleased section while
|
|
303
|
+
VERSION stays at the previous beta; the tag validator always rejects entry
|
|
304
|
+
files at the candidate release SHA, regardless of inline notes or the version.
|
|
196
305
|
|
|
197
306
|
### Preparing a release
|
|
198
307
|
|
|
@@ -205,9 +314,9 @@ One command per transition. It never commits, tags, pushes, or publishes.
|
|
|
205
314
|
| Release candidate to the release | `bin/rake "release:prepare[2.0.0]"` |
|
|
206
315
|
| After the release publishes, reopen development | `bin/rake "release:reopen[2.1.0.alpha]"` |
|
|
207
316
|
|
|
208
|
-
`release:prepare` refuses a dirty working tree, a version that moves backwards, a version whose base is not the line `main` is developing, and an alpha target. It then bumps VERSION, folds `## [Unreleased]` into `## [<version>] - <date>` with one block per `###` heading, restates the fences, regenerates the surface inventory, and prints the tag and dispatch commands. Every rewrite is computed before any of it is written, so a refusal leaves the working tree untouched.
|
|
317
|
+
`release:prepare` refuses a dirty working tree, a version that moves backwards, a version whose base is not the line `main` is developing, and an alpha target. It then bumps VERSION, folds `## [Unreleased]` and optional entry files into `## [<version>] - <date>` with one block per `###` heading, restates the fences, regenerates the surface inventory, and prints the tag and dispatch commands. Every rewrite is computed before any of it is written, so a refusal leaves the working tree untouched.
|
|
209
318
|
|
|
210
|
-
A final release also absorbs every prerelease section of its own base version. Cutting `2.0.0` folds `## [2.0.0.beta1]` and `## [2.0.0.rc1]` into `## [2.0.0] - <date>` and removes their headings, prerelease entries first and anything written after them second, so the notes a user reads for 2.0.0 are the whole story rather than three fragments. An empty `## [Unreleased]` is therefore legitimate for a final release cut straight from a release candidate. A beta or a release candidate has nothing to absorb, so an empty Unreleased section refuses: there is nothing new to publish.
|
|
319
|
+
A final release also absorbs every prerelease section of its own base version. Cutting `2.0.0` folds `## [2.0.0.beta1]` and `## [2.0.0.rc1]` into `## [2.0.0] - <date>` and removes their headings, prerelease entries first and anything written after them second, so the notes a user reads for 2.0.0 are the whole story rather than three fragments. An empty `## [Unreleased]` is therefore legitimate for a final release cut straight from a release candidate. A beta or a release candidate has nothing to absorb, so an empty Unreleased section without entry files refuses: there is nothing new to publish.
|
|
211
320
|
|
|
212
321
|
Review the diff and run the release contracts:
|
|
213
322
|
|
|
@@ -225,17 +334,123 @@ A release is pinned by its tag, never by a branch:
|
|
|
225
334
|
|
|
226
335
|
| Step | Command | What guards it |
|
|
227
336
|
|---|---|---|
|
|
228
|
-
| Tag the merge commit | `git tag v<version> <merge-sha> && git push origin v<version>` (lightweight or annotated both work) | `script/validate-release` requires the tag to sit on `main` history, match `Woods::VERSION`, match the dated `CHANGELOG.md` heading, and not be an alpha |
|
|
229
|
-
| Trigger the release workflow | `gh api --method POST repos/lost-in-the/woods/dispatches -f event_type=release -F 'client_payload[tag]=v<version>' -F 'client_payload[ci_run_id]=<id>'` where `<id>` is the green CI run on the
|
|
337
|
+
| Tag the merge commit | `git tag v<version> <merge-sha> && git push origin v<version>` (lightweight or annotated both work) | `script/validate-release` requires the tag to sit on `main` history (or the explicitly approved maintenance history below), match `Woods::VERSION`, match the dated `CHANGELOG.md` heading, and not be an alpha |
|
|
338
|
+
| Trigger the release workflow | `gh api --method POST repos/lost-in-the/woods/dispatches -f event_type=release -F 'client_payload[tag]=v<version>' -F 'client_payload[ci_run_id]=<id>'` where `<id>` is the green CI run the tag push itself started, the one whose branch column reads `v<version>`; main's run on the same commit is refused with `tested ref is main` (requires Contents write) | `.github/workflows/release.yml` re-validates the named CI run through the API, verifies the artifact digest, and runs secret-free candidate package tests before publishing |
|
|
230
339
|
| Verify publication | `gem info woods --remote` shows the new version; for a prerelease, `gem info woods --remote --prerelease`. The README gem badge updates on its own | just before pushing, the workflow re-runs `script/verify-release-tag` so a tag that moved since validation aborts the publish |
|
|
231
340
|
|
|
232
341
|
Nothing is published from a laptop: the workflow builds and pushes the gem from the validated CI artifact, so the bytes on RubyGems are the bytes CI tested. `rake release` and `rake release:rubygem_push`, which `bundler/gem_tasks` installs, are blocked for that reason.
|
|
233
342
|
|
|
234
343
|
After a final release publishes, reopen development with `release:reopen` in a follow-up pull request.
|
|
235
344
|
|
|
345
|
+
### When a dispatch fails
|
|
346
|
+
|
|
347
|
+
`release-context` and `publish` both check out `github.sha`, the default
|
|
348
|
+
branch's tip at dispatch time, not the tag: `release-context` re-validates the
|
|
349
|
+
named CI run, checks the live `release` environment, and runs
|
|
350
|
+
`script/validate-release`; `publish` runs `script/verify-release-tag` and
|
|
351
|
+
pushes the downloaded artifact. Only `package-test` checks out
|
|
352
|
+
`needs.release-context.outputs.release-sha`, the tag's own commit, because
|
|
353
|
+
that is what CI actually built and tested. The gem bytes `publish` pushes were
|
|
354
|
+
built by CI at `release-sha`; `publish` never rebuilds them.
|
|
355
|
+
|
|
356
|
+
That split decides the fix for a failed dispatch:
|
|
357
|
+
|
|
358
|
+
| What failed | Lives in | Fix |
|
|
359
|
+
|---|---|---|
|
|
360
|
+
| `script/validate-release-run`, `script/validate-release`, `script/verify-release-tag`, or the workflow files themselves | main, read at `github.sha` | merge the fix to main, then re-dispatch at the same tag; the tag never moves |
|
|
361
|
+
| Live `release` environment settings (protection rule, admin bypass) | GitHub environment configuration, not the tree | fix the setting directly; no commit or re-dispatch needed |
|
|
362
|
+
| Anything under `spec/` or `lib/` that `package-test` actually runs against the candidate | the tagged commit, read at `release-sha` | a main-only fix does not reach the candidate; merge it, then move the tag to the new main tip and get a fresh CI run on it |
|
|
363
|
+
|
|
364
|
+
Both failure classes happened in the beta1 dispatch: a `REQUIRED_CI_JOBS`
|
|
365
|
+
prefix left behind by a `ci.yml` job rename was a validator fix that needed
|
|
366
|
+
only a merge and a re-dispatch; two `packaged_gem_spec.rb` smoke failures
|
|
367
|
+
traced to hard-coded `2.0.0` literals needed the tag moved to the commit that
|
|
368
|
+
fixed them, because the candidate job runs the spec file at the tag.
|
|
369
|
+
|
|
370
|
+
**Moving a tag is acceptable only before publication.** Once `publish` has
|
|
371
|
+
pushed the gem to RubyGems, the tag is the permanent, immutable record of what
|
|
372
|
+
was published; move it before that point only, with
|
|
373
|
+
`git tag -f v<version> <new-sha> && git push --force origin v<version>` run by
|
|
374
|
+
the maintainer, followed by a fresh CI run on the new tag SHA before
|
|
375
|
+
re-dispatching.
|
|
376
|
+
|
|
377
|
+
### Publishing the GitHub Release entry
|
|
378
|
+
|
|
379
|
+
The workflow deliberately creates no GitHub Release: the API cannot bind an
|
|
380
|
+
existing tag to an expected commit atomically, so automating it would race the
|
|
381
|
+
tag's own verification. Once `gem info woods --remote` (or `--remote
|
|
382
|
+
--prerelease`) confirms publication, create the entry by hand:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
gh release create v<version> --verify-tag --notes-file <file> # release
|
|
386
|
+
gh release create v<version> --verify-tag --prerelease --notes-file <file> # beta or rc
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
`--verify-tag` refuses if the tag is missing or moved. Write `<file>` as a
|
|
390
|
+
short body that links `CHANGELOG.md` at the tag itself (not at `main`) and
|
|
391
|
+
anchors straight to that version's dated heading, so the note a reader lands
|
|
392
|
+
on always matches the bytes RubyGems published.
|
|
393
|
+
|
|
394
|
+
### One-off 1.6.2 security maintenance release
|
|
395
|
+
|
|
396
|
+
The [security policy](SECURITY.md#supported-versions) supports 1.6.x security
|
|
397
|
+
fixes until 2027-02-20. While main develops v2, the sole maintenance exception
|
|
398
|
+
is `v1.6.2` from the short-lived `release/1.6.2` branch, descending from the
|
|
399
|
+
immutable v1.6.1 commit `73423a42644176b09961be373e13648c94690933`.
|
|
400
|
+
This is a stable patch, separate from the next v2 prerelease; it does not declare
|
|
401
|
+
v2 final or establish a general-purpose maintenance publishing path.
|
|
402
|
+
|
|
403
|
+
`script/release_profile.rb` on trusted main owns this exact tag/branch/base and
|
|
404
|
+
its required CI jobs. `MAINTENANCE_APPROVED_SHA` starts as `nil`: publication
|
|
405
|
+
fails closed until a **separate reviewed main PR** pins the exact prepared
|
|
406
|
+
maintenance commit. Neither a dispatch parameter nor candidate code can choose
|
|
407
|
+
another profile, branch, base, SHA or weaker CI requirements. The SHA binds the
|
|
408
|
+
whole reviewed candidate, including its CI definition and installed-package
|
|
409
|
+
tests; review those files as release controls, not just their job names.
|
|
410
|
+
|
|
411
|
+
The preparation order is:
|
|
412
|
+
|
|
413
|
+
1. Merge the main-side maintenance policy/tooling PR. Before creating the remote
|
|
414
|
+
target, confirm its effective branch rules require pull requests and prevent
|
|
415
|
+
force pushes and deletion; configure those rules before creating the target. The GitHub
|
|
416
|
+
rules API can check `release/1.6.2` before the branch exists.
|
|
417
|
+
2. Create that target from the immutable v1.6.1 commit. Review the narrow security
|
|
418
|
+
backport and its legacy preparation adapter against that line. Disable the
|
|
419
|
+
inherited automatic tag-push publisher before any maintenance tag exists.
|
|
420
|
+
3. Use the legacy adapter's `release:reopen[1.6.2.alpha]` and
|
|
421
|
+
`release:prepare[1.6.2]` transitions in clean, separately reviewed commits.
|
|
422
|
+
The adapter owns the legacy documentation profile; do not copy v2 fences or
|
|
423
|
+
surface claims into v1, and never hand-edit VERSION.
|
|
424
|
+
4. Review and merge the prepared candidate into `release/1.6.2`. Require passing
|
|
425
|
+
unit, booted Rails, installed-package, lint, coverage, security and build
|
|
426
|
+
jobs. Review the complete CI and package-test implementation at that SHA.
|
|
427
|
+
Then pin that **exact final commit** in `MAINTENANCE_APPROVED_SHA` through the
|
|
428
|
+
separate main PR. No pin means no maintenance release.
|
|
429
|
+
5. Only after the pin merges, the maintainer may tag that exact commit and wait
|
|
430
|
+
for its tag-push CI run. Dispatch uses the ordinary tag/run-ID payload.
|
|
431
|
+
Every exact maintenance matrix row in the trusted profile must succeed;
|
|
432
|
+
missing, duplicated, skipped or failed rows refuse publication.
|
|
433
|
+
|
|
434
|
+
The validators require the approved SHA to remain reachable from the freshly
|
|
435
|
+
fetched maintenance branch and to descend from the fixed legacy base. They retain
|
|
436
|
+
exact tag/VERSION/changelog checks, the unpublished-version check, one immutable
|
|
437
|
+
CI artifact ID/digest, and protected `release` environment approval. Both Ruby
|
|
438
|
+
package-test rows install that same artifact and run the pinned v1-specific
|
|
439
|
+
`maintenance_packaged_gem_spec.rb` outside the repository load path. The oldest
|
|
440
|
+
Ruby maintenance row explicitly activates MCP 0.23.0, the reviewed security
|
|
441
|
+
floor; the latest row resolves the candidate's supported SDK range. Candidate
|
|
442
|
+
code still executes only in secret-free, read-only jobs. After environment
|
|
443
|
+
approval, maintenance history/publication checks run again before requesting
|
|
444
|
+
RubyGems credentials; the remote tag is checked again immediately before push.
|
|
445
|
+
|
|
446
|
+
A candidate fix or changed prepared SHA requires a new reviewed main pin and a
|
|
447
|
+
fresh tag-push CI run. Updating main's tooling alone never authorizes different
|
|
448
|
+
candidate bytes. Main's v2 release contract remains unchanged. Do not create or
|
|
449
|
+
push tags, dispatch, publish, or claim 1.6.2 is available during preparation.
|
|
450
|
+
|
|
236
451
|
### Stable branches
|
|
237
452
|
|
|
238
|
-
A stable branch is `N-M-stable`, cut from the release tag. Create one only when a released line needs a patch after a newer major has shipped on `main`; until then, `main` is the
|
|
453
|
+
A stable branch is `N-M-stable`, cut from the release tag. Create one only when a released line needs a patch after a newer major has shipped on `main`; until then, `main` is the development branch. The explicitly approved short-lived `release/1.6.2` security exception above does not establish an `N-M-stable` branch.
|
|
239
454
|
|
|
240
455
|
### What coding agents may do
|
|
241
456
|
|
data/README.md
CHANGED
|
@@ -15,15 +15,15 @@
|
|
|
15
15
|
>
|
|
16
16
|
> `main` is the development branch and can run ahead of the latest published gem. The gem badge above shows the latest published version; documentation for a published version lives on its tag.
|
|
17
17
|
>
|
|
18
|
-
> ### Version: 2.0.0.
|
|
18
|
+
> ### Version: 2.0.0.beta3 is published as a prerelease; `main` documents 2.0.0
|
|
19
19
|
>
|
|
20
20
|
> | Line | Version | Documentation |
|
|
21
21
|
> |---|---|---|
|
|
22
22
|
> | Documented here | **2.0.0**, unreleased | this README and the [documentation index](docs/README.md) |
|
|
23
|
-
> | Latest prerelease | **2.0.0.
|
|
23
|
+
> | Latest prerelease | **2.0.0.beta3** | [the v2.0.0.beta3 tag](https://github.com/lost-in-the/woods/tree/v2.0.0.beta3) |
|
|
24
24
|
> | Latest published gem | **1.6.1** | [the v1.6.1 tag](https://github.com/lost-in-the/woods/tree/v1.6.1) |
|
|
25
25
|
>
|
|
26
|
-
> RubyGems treats 2.0.0.
|
|
26
|
+
> RubyGems treats 2.0.0.beta3 as a prerelease, so `gem "woods", "~> 2.0"` does not resolve it. Install it explicitly with `gem "woods", "2.0.0.beta3"`. The released constraint stays `gem "woods", "~> 1.6"`.
|
|
27
27
|
<!-- release-state:end -->
|
|
28
28
|
|
|
29
29
|
Woods boots your Rails app, extracts the behavior Rails assembles at runtime, and serves it to AI tools through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). Agents can inspect resolved routes, schema, associations, callbacks, included concerns, dependencies, and execution flows instead of guessing from source files alone.
|
|
@@ -62,6 +62,10 @@ The default setup provides structural code intelligence. It does not require an
|
|
|
62
62
|
|
|
63
63
|
### 1. Install Woods
|
|
64
64
|
|
|
65
|
+
First [choose a version that is published on RubyGems](docs/GETTING_STARTED.md#1-install-the-gem).
|
|
66
|
+
The example below requires a stable 2.x release; beta and release-candidate
|
|
67
|
+
installations need an exact published prerelease pin from that guide.
|
|
68
|
+
|
|
65
69
|
```ruby
|
|
66
70
|
# Gemfile
|
|
67
71
|
group :development do
|
data/SECURITY.md
CHANGED
|
@@ -60,11 +60,12 @@ Woods runs inside your Rails application and has access to:
|
|
|
60
60
|
- **Application source code**: extracted and written to the output directory as JSON
|
|
61
61
|
- **Database schema**: column names, types, indexes, and foreign keys (no row data)
|
|
62
62
|
- **Git metadata**: commit history, contributors, file change frequency
|
|
63
|
-
- **
|
|
63
|
+
- **Optional session traces**: session/trace identifiers, request paths and controller/action timelines when session tracing is configured
|
|
64
|
+
- **Live database rows** (Console MCP Server), queries within a rolled-back transaction
|
|
64
65
|
|
|
65
66
|
### Output Directory
|
|
66
67
|
|
|
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
|
|
68
|
+
Extracted data is written to `tmp/woods/` by default. This directory contains your application's source code and schema in structured JSON format. Source literals, comments and configuration metadata may contain sensitive values. Treat the index with the same sensitivity as your source code; do not expose it to untrusted parties. Optional session stores can be configured under this directory and add request metadata that may be more sensitive than the source itself. Apply the [session tracing access and retention guidance](docs/CONFIGURATION_REFERENCE.md#session-tracer-options) to those stores too.
|
|
68
69
|
|
|
69
70
|
### Console Server
|
|
70
71
|
|
|
@@ -80,13 +81,15 @@ If extraction output leaks, what can an attacker do with it?
|
|
|
80
81
|
|
|
81
82
|
**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
|
|
|
83
|
-
**
|
|
84
|
+
**Structural extraction boundaries.** Structural extraction collects schema rather than dumping live database rows, and does not intentionally collect environment variables or the Rails encrypted credential store. This is not a guarantee that output is free of secrets or customer information: extracted source can contain hardcoded values, comments or examples, and Index tools can return that source. Console redaction and export-specific scrubbing do not sanitize the structural index.
|
|
85
|
+
|
|
86
|
+
**Optional session data.** When configured, session tracing records session/trace identifiers, request paths and controller/action timelines. Request paths and identifiers can contain sensitive user information. The configured session store controls where these records live; configured Index session tools can return them. Session storage and access need their own retention and authorization controls. Console MCP is a separate live-data boundary described above.
|
|
84
87
|
|
|
85
88
|
| Leak scenario | Attacker gains | Attacker does not gain |
|
|
86
89
|
|---|---|---|
|
|
87
|
-
| `tmp/woods/` directory exfiltrated | Source code
|
|
88
|
-
| MCP Index Server token leaked (HTTP transport) |
|
|
90
|
+
| `tmp/woods/` directory exfiltrated | Source code, schema and metadata, including sensitive values present in source; session records if their store is configured here | No additional live database or shell access merely from possessing these files |
|
|
91
|
+
| MCP Index Server token leaked (HTTP transport) | Access to published source/metadata and configured session tools, including sensitive content they contain | The packaged default does not boot Rails or provide live database queries or shell execution; custom tool wiring has its own access boundary |
|
|
89
92
|
| 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) |
|
|
93
|
+
| Console MCP Server exposed (dev/staging) | Live database access constrained by TableGate, credential scanning, Redactor and SqlValidator; this remains admin-trust access | Supported packaged modes expose no write or eval tools; rollback and redaction have the limits described in the Console guide |
|
|
91
94
|
|
|
92
95
|
**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.
|
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.
|