Skip to main content
/ The module

The brain & semantic search

Droost's knowledge of a site is four stores that know about each other, all built from the code and the running site rather than from training data. drush droost:doctor reports the freshness of each one and the exact command to rebuild it.

The brain

drush droost:brain:build harvests what the installed modules provide and define: plugin types with a real example class to copy, entity types, services with their classes and deprecations, routes with handlers, hook implementations, event listeners, config-schema types and module dependencies. It serves droost_capabilities, droost_architecture and droost_module_patterns.

The brain is a union of two sources. A shipped core seed (droost_knowledge, version-keyed per core major) is the floor, so a fresh install answers canonical core questions before the first build. The per-project harvest is the truth, and wins on collision.

Search and the code graph

drush droost:search:index builds two things over core, contrib, custom code and the wiki:

  • Lexical and semantic search. Lexical is a complete store on its own. Semantic needs an embedding backend (Ollama, or anything OpenAI-compatible); without one the semantic index is explained where it happens rather than silently empty.
  • A code graph. Symbols and six framework-semantic edge kinds: service_class and injects from *.services.yml, routes_to from routing files, implements_hook, uses_service (the \Drupal::service('literal') id), derived_by. This is what lets droost_search answer "who calls this?" and lets the seeker follow a change one hop to its consumers.

Indexing is incremental: a per-file hash manifest means only added and changed files re-parse, and removed files drop their rows. --full forces a rebuild, and a bump of the indexer version does so automatically.

Lexical search works with no setup. Semantic search (embedding KNN over the same index) needs an embedding backend, and Droost does not require the Drupal AI module for it. You choose the backend with embedding_backend in droost.search.settings:

  • builtin: Droost talks directly to an embedding HTTP endpoint you run or point at, with no extra module. This is the no-dependency path.
  • ai: reuse the embeddings provider the Drupal AI module already has configured, through the optional droost_ai submodule. The right choice when the site runs drupal/ai anyway.
  • none: lexical only, semantic off.
  • auto (the default): use the AI backend when droost_ai is enabled and available, otherwise the built-in one when an endpoint is set, otherwise lexical only.

Built-in, against a local Ollama

Nothing leaves the machine and there is no paid API:

bash
ollama pull nomic-embed-text          # once: an embedding model
drush config:set droost.search.settings embedding_backend builtin
drush config:set droost.search.settings embedding_format   ollama
drush config:set droost.search.settings embedding_endpoint http://localhost:11434
drush config:set droost.search.settings embedding_model    nomic-embed-text
drush droost:search:index --full

From inside DDEV or Docker the host's Ollama is usually reachable at http://host.docker.internal:11434.

Built-in, against an OpenAI-compatible endpoint

Any /v1/embeddings server (OpenAI itself, or a local vLLM or LM Studio):

bash
drush config:set droost.search.settings embedding_backend builtin
drush config:set droost.search.settings embedding_format   openai
drush config:set droost.search.settings embedding_endpoint https://api.openai.com
drush config:set droost.search.settings embedding_model    text-embedding-3-small
drush config:set droost.search.settings embedding_api_key  sk-...
drush droost:search:index --full

Through the Drupal AI module

When the site already runs drupal/ai with an embeddings provider, enable the bridge and let it reuse that connection rather than configuring a second one:

bash
composer require drupal/ai
drush en droost_ai -y
drush config:set droost.search.settings embedding_backend ai   # or leave it 'auto'
drush droost:search:index --full

drush droost:doctor reports whether semantic search is actually working and, when it is not, the exact setting to change. A backend that is configured but unreachable is a fault it names; lexical-only is a legitimate state it reports without alarm.

The wiki

The project's own documentation, as a bundle of Markdown pages at droost/wiki (configurable through droost.wiki.settings.path). Each page carries provenance: the modules it documents, the commit and the content hashes it was verified against. A page whose provenance no longer matches the code is reported stale, never served as fresh.

droost_wiki_write lets an agent write a page whose provenance Droost composes from the factsheet and the current commit, then re-verifies and rolls back if it does not check out. The workflow's wiki_fresh gate asks at completion whether the docs still match the code that was just written.

Staying fresh

The base module reacts to change instead of waiting to be pulled. Installing or uninstalling a module, and a drift of the git HEAD detected on cron, enqueue brain builds and incremental re-indexes onto a queue worker. Wiki staleness is reported, never auto-regenerated, so LLM cost stays an operator's decision.

bash
drush droost:doctor            # one verdict per store, and what to run
drush droost:brain:build
drush droost:search:index      # incremental; --full to rebuild
Verified against droost 2.0.0-alpha4 · workflow 0.6.9 · 2026-09-03