Drupaltools Code Search: Install, Source and Security | FunnelSlayer

Drupaltools Code Search

Published by drupaltools in skills

Review recommended22 installs

What this skill does

Search the source code of all Drupal contributed modules on drupal.org via the GitLab API. Use this skill whenever the user wants to find code examples, usage patterns, or implementations in Drupal contrib modules - e.g. "find examples of hook_form_alter in contrib", "which modules use a specific class or interface", "show me how contrib modules implement X". Trigger even for vague requests like "how do contrib modules do X" or "find me a real-world example of Y in Drupal".

Add Drupaltools Code Search to your agent

Review the source and files first. When you are ready, copy the prompt instruction or use the CLI command supported by your environment.

Install with a prompt

Paste this into a compatible coding agent:

add this skill "drupaltools-code-search" from https://github.com/drupaltools/skills

Install with the CLI

Run this command in a controlled environment after reviewing the repository:

npx skills add https://github.com/drupaltools/skills --skill drupaltools-code-search

Skill instructions

Drupal Contrib Code Search

Search all Drupal contributed modules on git.drupalcode.org using the GitLab Blobs API.

Notice that `<TERM>`` is the keywords we search for. This is the code selection I have provided.

Base search URL

https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=<TERM>&per_page=100&page=1

Always append these exclusions to avoid duplicates (modules bundled inside other projects):

-path:web/* -path:core/* -path:docroot -path:modules/contrib/*

Full base command:

curl -sS \
  --header "PRIVATE-TOKEN: $DRUPALORG_GITLAB_TOKEN" \
  "https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=<TERM>%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1"

Input validation

Before building the search URL:

  1. Empty term - refuse and ask for a search term.
  2. Term is only Drupal core paths (e.g. core/lib/) - warn the user; these are excluded by default.
  3. URL-encode the term - spaces → %20, " → %22, | → %7C, + → %2B, * stays *.
  4. Response validation - if the API returns non-200 or an empty array [], report it clearly:
    • 401 → "Token invalid or expired."
    • 403 → "Token lacks read_api scope."
    • 404 → "Group not found - check group ID 2."
    • Empty array → "No results found. Try a broader or different term."

Search syntax

SyntaxDescriptionExample
"exact phrase"Exact match"hook_form_alter"
~Fuzzy matchEntityTypeManger~
|ORhook_install | hook_update_N
+AND (both terms required)plugin +annotation
-Exclude termcache -backend
*Wildcard / partialEntityType*
\Escape special char\*md
filename:Filter by filename patternfilename:*.routing.yml
path:Filter by repo pathpath:src/Plugin/Block/
extension:Filter by file extension (exact)extension:php

Optimizations

  • Prefer return URLs for a specific branch or git tag and not for a random UUID version. For example this URL: https://git.drupalcode.org/project/webform_views/-/blob/1ec1904a3035027cc056d46ad941db4d8b1e7a85/src/Plugin/views/field/WebformSubmissionNotesEditField.php#L7 should return the first default branch equivalent which is https://git.drupalcode.org/project/webform_views/-/blob/8.x-5.x/src/Plugin/views/field/WebformSubmissionNotesEditField.php?ref_type=heads#L7 in this case.

Common search patterns with example URLs

Find all uses of a hook

hook_form_alter -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=hook_form_alter%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

Find implementations of a specific interface (PHP only)

implements TokenInterface extension:php -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=implements%20TokenInterface%20extension:php%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

Find a service definition in YAML

"my_module.service" extension:yml -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=%22my_module.service%22%20extension:yml%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

Find Block plugins

path:src/Plugin/Block/ extension:php -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=path:src/Plugin/Block/%20extension:php%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

Find routing files that reference a specific controller

_controller filename:*.routing.yml -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=_controller%20filename:*.routing.yml%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

Find modules using a specific Composer package

symfony/http-foundation -filename:composer.lock -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=symfony/http-foundation%20-filename:composer.lock%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

Find schema definitions for a config key

"field.field." filename:*.schema.yml -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=%22field.field.%22%20filename:*.schema.yml%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

OR search: two alternative hooks

hook_install | hook_uninstall -path:web/* -path:core/* -path:docroot -path:modules/contrib/*

URL: https://git.drupalcode.org/api/v4/groups/2/search?scope=blobs&search=hook_install%20%7C%20hook_uninstall%20-path:web/*%20-path:core/*%20-path:docroot%20-path:modules/contrib/*&per_page=100&page=1

Pagination

The API returns up to 100 results per page. To fetch the next page, increment page=:

&per_page=100&page=2

If the result count equals per_page, there may be more pages.

Presenting results

Each result contains:

  • project_id - GitLab project (module) ID
  • ref - branch
  • filename - file path in the repo
  • startline - line number of the match
  • data - snippet of matched content

Construct a human-readable link:

https://git.drupalcode.org/project/<MODULE_NAME>/-/blob/<REF>/<FILENAME>#L<STARTLINE>

To get <MODULE_NAME>, use:

curl -sS --header "PRIVATE-TOKEN: $DRUPALORG_GITLAB_TOKEN" "https://git.drupalcode.org/api/v4/projects/<project_id>"

and read the path_with_namespace or name field.

Getting stable branch/tag URLs

The API returns commit hashes (ref) which create unstable URLs. To get the default branch:

curl -sS --header "PRIVATE-TOKEN: $DRUPALORG_GITLAB_TOKEN" \
  "https://git.drupalcode.org/api/v4/projects/<project_id>/repository/branches" | jq -r '.[0].name // "main"'

For the latest release tag:

curl -sS --header "PRIVATE-TOKEN: $DRUPALORG_GITLAB_TOKEN" \
  "https://git.drupalcode.org/api/v4/projects/<project_id>/repository/tags" | jq -r '[.[] | select(.name | test("^[0-9]"))][0].name'

Then construct stable URLs:

https://git.drupalcode.org/project/<MODULE_NAME>/-/blob/<BRANCH_OR_TAG>/<FILENAME>?ref_type=heads#L<STARTLINE>

Always show the user:

  1. The direct full link to the file on git.drupalcode.org.
  2. The matching snippet from data.
  3. The module name (not just the project ID).

CLI Tool

A Python CLI tool dsearch.py is available for quick searches without invoking this skill.

Usage

# Basic search
./dsearch.py "WebformSubmissionInterface"

# Limit results
./dsearch.py "hook_form_alter" --limit 5

# Filter by file extension
./dsearch.py "EntityTypeManager" --extension php

# Output as JSON
./dsearch.py "WebformHandler" --json

# Show all results (up to 100)
./dsearch.py "FormElement" --all

# Use faster unstable URLs (commit hashes)
./dsearch.py "TokenInterface" --no-branch

The CLI tool reads DRUPALORG_GITLAB_TOKEN from .env and automatically:

  • Fetches module names
  • Gets default branches for stable URLs
  • Formats output with colors
  • Shows code snippets

Files included

  • dsearch.py
  • SKILL.md

More skills