Skip to content

feat(descriptions): intent-first tool descriptions with dynamic Related resolution #169

@polaz

Description

@polaz

Summary

Rewrite all 32 remaining tool descriptions from old UPPERCASE PREFIX format to intent-first agentic format with dynamic cross-references. The "Related:" section in descriptions must be resolved at runtime — references to disabled tools (via USE_*, GITLAB_DENIED_TOOLS_REGEX, tier/version gating, or all-actions-denied) are automatically stripped.

Scope: 32 tool descriptions + 1 implementation change + ~60 test assertions + documentation

Problem

After partial implementation in #149 (commit 82718ab), only 10/44 tools have the new intent-first format. The remaining 32 use old UPPERCASE PREFIX style ("BROWSE labels...", "MANAGE pipelines..."), which:

  1. Wastes context — "BROWSE" and "MANAGE" prefixes are redundant (tool names already contain this info)
  2. Missing disambiguation — agents confuse browse_users vs browse_members, browse_commits vs browse_refs
  3. No cross-references — agents don't discover related tools (e.g., don't know manage_pipeline_job exists when looking at browse_pipelines)
  4. Static references — current "Related:" in the 10 updated tools reference tools that may be disabled, creating dead-end hints

Implementation: Dynamic Related Resolution

Architecture

Add a second pass to buildToolLookupCache() in src/registry-manager.ts that strips "Related:" references to unavailable tools:

private buildToolLookupCache(): void {
  this.toolLookupCache.clear();

  // ... existing first pass: filter tools and add to cache ...

  // Second pass: resolve Related references against available tools
  const availableToolNames = new Set(this.toolLookupCache.keys());
  for (const [toolName, tool] of this.toolLookupCache) {
    const resolved = resolveRelatedReferences(tool.description, availableToolNames);
    if (resolved !== tool.description) {
      this.toolLookupCache.set(toolName, { ...tool, description: resolved });
    }
  }
}

Resolution Function

New utility in src/utils/description-utils.ts:

/**
 * Strip "Related:" section references to unavailable tools.
 * If all referenced tools are unavailable, the entire "Related:" clause is removed.
 *
 * Format: "... Related: tool_name purpose, tool_name2 purpose."
 * Multiple items separated by commas. Each starts with a tool name (browse_*/manage_*).
 */
export function resolveRelatedReferences(
  description: string,
  availableTools: Set<string>
): string {
  const relatedMatch = description.match(/\s*Related:\s*(.+?)\.?\s*$/);
  if (!relatedMatch) return description;

  const baseDescription = description.substring(0, relatedMatch.index!);
  const relatedContent = relatedMatch[1];

  // Split by comma, keep only items whose tool is available
  const items = relatedContent.split(",").map((s) => s.trim());
  const available = items.filter((item) => {
    const toolRef = item.match(/^((?:browse|manage)_\w+)\b/);
    return toolRef && availableTools.has(toolRef[1]);
  });

  if (available.length === 0) {
    return baseDescription.trimEnd();
  }

  return `${baseDescription.trimEnd()} Related: ${available.join(", ")}.`;
}

Gating Scenarios Handled

Scenario Effect on Related
USE_MRS=false browse_pipelines description drops "Related: manage_pipeline..." since manage_pipeline is also gated
GITLAB_DENIED_TOOLS_REGEX="manage_.*" All "Related: manage_X..." references stripped
GITLAB_READ_ONLY_MODE=true All manage_* tools filtered, so "Related: manage_X..." stripped
Tier gating removes tool Related reference stripped
GITLAB_DENIED_ACTIONS removes ALL actions Tool effectively removed, Related stripped
Custom GITLAB_TOOL_* override Overrides entire description including Related (user controls)

New Tool Descriptions (32 tools)

Format Rules

[Intent verb phrase]. Actions: [action (explanation), ...]. [Related: tool_name purpose, tool_name2 purpose.]
  • Intent first: what the agent should use this tool for (verb phrase)
  • Actions: concise parenthetical explanations, no quotes around action names
  • Related: only for disambiguation or non-obvious pairings; omit trailing period if removed at runtime

Files Entity (src/entities/files/registry.ts)

browse_files:

Explore project file structure and read source code. Actions: tree (list directory contents with recursive depth control), content (read file at specific ref/branch), download_attachment (get uploaded file by secret+filename). Related: manage_files to create/update files.

manage_files:

Create, update, or upload repository files. Actions: single (create/update one file with commit message), batch (atomic multi-file commit), upload (add attachment returning markdown link). Related: browse_files to read existing files.

MRs Entity (src/entities/mrs/registry.ts)

browse_merge_requests:

Find and inspect merge requests. Actions: list (filter by state/author/reviewer/labels/branch), get (MR details by IID or source branch), diffs (file-level changes with inline suggestions), compare (diff between any two refs). Related: manage_merge_request to create/update/merge.

browse_mr_discussions:

Read discussion threads and draft review notes on merge requests. Actions: list (all threads with resolution status), drafts (unpublished draft notes), draft (single draft details). Related: manage_mr_discussion to comment, manage_draft_notes to create drafts.

manage_merge_request:

Create, update, merge, or approve merge requests. Actions: create (new MR from source to target), update (title/description/assignees/reviewers/labels), merge (into target branch), approve/unapprove (review approval), get_approval_state (current approvals). Related: browse_merge_requests for discovery.

manage_mr_discussion:

Post comments, start threads, and suggest code changes on merge requests. Actions: comment (simple note), thread (line-level discussion), reply (to existing thread), update (edit note text), resolve (toggle thread resolution), suggest (code suggestion block), apply_suggestion/apply_suggestions (accept code suggestions). Related: browse_mr_discussions to read threads.

manage_draft_notes:

Create and manage unpublished review comments on merge requests. Actions: create (new draft), update (modify text), publish (make single draft visible), publish_all (submit entire review), delete (discard draft). Related: browse_mr_discussions action 'drafts' to list existing drafts.

Labels Entity (src/entities/labels/registry.ts)

browse_labels:

List and inspect project or group labels. Actions: list (all labels with search filtering), get (single label by ID or name). Related: manage_label to create/update/delete.

manage_label:

Create, update, or delete project/group labels. Actions: create (name + hex color required), update (modify properties), delete (remove permanently). Related: browse_labels for discovery.

Pipelines Entity (src/entities/pipelines/registry.ts)

browse_pipelines:

Monitor CI/CD pipelines and read job logs. Actions: list (filter by status/ref/source/username), get (pipeline details), jobs (list pipeline jobs), triggers (bridge/trigger jobs), job (single job details), logs (job console output). Related: manage_pipeline to trigger/retry/cancel, manage_pipeline_job for individual jobs.

manage_pipeline:

Trigger, retry, or cancel CI/CD pipelines. Actions: create (run pipeline on ref with variables), retry (re-run failed jobs), cancel (stop running pipeline). Related: browse_pipelines for monitoring.

manage_pipeline_job:

Control individual CI/CD jobs within a pipeline. Actions: play (trigger manual/delayed job with variables), retry (re-run single job), cancel (stop running job). Related: browse_pipelines actions 'job'/'logs' for job details.

Snippets Entity (src/entities/snippets/registry.ts)

browse_snippets:

Find and read code snippets with versioning support. Actions: list (personal/project/public scope with filtering), get (snippet metadata or raw file content). Related: manage_snippet to create/update.

manage_snippet:

Create, update, or delete code snippets with multi-file support. Actions: create (new snippet with files and visibility), update (modify content/metadata, file operations), delete (remove permanently). Related: browse_snippets for discovery.

Variables Entity (src/entities/variables/registry.ts)

browse_variables:

List and inspect CI/CD variables for projects or groups. Actions: list (all variables with pagination), get (single variable by key with environment scope filter). Related: manage_variable to create/update/delete.

manage_variable:

Create, update, or delete CI/CD variables with environment scoping. Actions: create (key + value, set scope/protection/masking), update (modify value or settings), delete (remove permanently). Related: browse_variables for discovery.

Wiki Entity (src/entities/wiki/registry.ts)

browse_wiki:

Read wiki pages in projects or groups. Actions: list (all pages with metadata), get (page content by slug). Related: manage_wiki to create/update/delete.

manage_wiki:

Create, update, or delete wiki pages. Actions: create (new page with title/content/format), update (modify content or title), delete (remove permanently). Related: browse_wiki to read pages.

Releases Entity (src/entities/releases/registry.ts)

browse_releases:

View project releases and asset download links. Actions: list (releases sorted by date), get (release details by tag name), assets (download link list for release). Related: manage_release to create/publish.

manage_release:

Create, update, or delete project releases with asset management. Actions: create (release from tag with notes/assets), update (modify metadata), delete (remove release, tag preserved), create_link (add asset URL), delete_link (remove asset). Related: browse_releases for discovery.

Refs Entity (src/entities/refs/registry.ts)

browse_refs:

Inspect branches, tags, and their protection rules. Actions: list_branches, get_branch, list_tags, get_tag, list_protected_branches, get_protected_branch, list_protected_tags (protection details and access levels). Related: manage_ref to create/delete/protect, browse_commits for commit history.

manage_ref:

Create, delete, and protect branches and tags. Actions: create_branch (from ref), delete_branch, protect_branch (set allowed roles), unprotect_branch, update_branch_protection, create_tag (annotated or lightweight), delete_tag, protect_tag, unprotect_tag. Related: browse_refs for inspection.

Members Entity (src/entities/members/registry.ts)

browse_members:

View team members and access levels in projects or groups. Actions: list_project, list_group, get_project, get_group (direct members), list_all_project, list_all_group (includes inherited). Levels: Guest(10), Reporter(20), Developer(30), Maintainer(40), Owner(50). Related: manage_member to add/remove, browse_users to find users by name.

manage_member:

Add, remove, or update access levels for project/group members. Actions: add_to_project, add_to_group (with access level + optional expiry), remove_from_project, remove_from_group, update_project, update_group (change access level). Related: browse_members for current membership.

Milestones Entity (src/entities/milestones/registry.ts)

browse_milestones:

Track milestone progress with associated issues and MRs. Actions: list (filter by state/title/search), get (milestone details), issues (items in milestone), merge_requests (MRs targeting milestone), burndown (chart data for sprint tracking). Related: manage_milestone to create/update.

manage_milestone:

Create, update, or delete project/group milestones. Actions: create (title + optional dates/description), update (modify properties or close/activate), delete (remove permanently), promote (elevate project milestone to group). Related: browse_milestones for progress tracking.

Integrations Entity (src/entities/integrations/registry.ts)

browse_integrations:

Discover active project integrations and their configuration. Actions: list (all active: Slack, Jira, Discord, Teams, Jenkins, etc.), get (specific integration settings by slug). Related: manage_integration to configure/disable.

manage_integration:

Configure or disable project integrations (50+ supported). Actions: update (enable/modify with integration-specific config), disable (deactivate integration). Note: gitlab-slack-application requires OAuth install from GitLab UI. Related: browse_integrations for discovery.

Webhooks Entity (src/entities/webhooks/registry.ts)

browse_webhooks:

List and inspect webhook configurations for projects or groups. Actions: list (all webhooks with event types and status), get (webhook details by ID). Related: manage_webhook to create/update/delete/test.

manage_webhook:

Create, update, delete, or test webhooks for event-driven automation. Actions: create (URL + event types + optional secret), update (modify settings), delete (remove), test (trigger delivery for specific event). Related: browse_webhooks for inspection.

Work Items Entity (src/entities/workitems/registry.ts)

browse_work_items:

Find and inspect issues, epics, tasks, and other work items. Actions: list (groups return epics, projects return issues/tasks, filter by type/state/labels), get (by numeric ID or namespace+iid from URL path). Related: manage_work_item to create/update/delete.

manage_work_item:

Create, update, delete, or link work items (issues, epics, tasks). Actions: create (epics need GROUP namespace, issues/tasks need PROJECT), update (widgets: dates, time tracking, weight, iterations, health, progress, hierarchy), delete (permanent), add_link/remove_link (BLOCKS/IS_BLOCKED_BY/RELATES_TO). Related: browse_work_items for discovery.

Search Entity (src/entities/search/registry.ts)

browse_search:

Search across GitLab resources globally or within a scope. Actions: global (entire instance), project (within specific project), group (within specific group). Searchable: projects, issues, merge_requests, milestones, users, blobs (code), commits, wiki_blobs, notes.

Context Entity (src/entities/context/registry.ts)

manage_context:

View and manage runtime session configuration. Actions: show (current host/preset/scope/mode), list_presets (available tool configurations), list_profiles (OAuth users), switch_preset (change active preset), switch_profile (change OAuth user), set_scope (restrict to namespace), reset (restore initial state).

Test Changes

Strategy

Replace old UPPERCASE checks with entity-keyword and action-word assertions. New tests verify:

  1. Description contains the entity domain keyword (not the prefix)
  2. Description mentions all expected actions
  3. Description format starts with intent verb (not uppercase label)

Files to Update (21 test files, ~80 assertions)

tests/unit/entities/files/registry.test.ts

- expect(tool?.description).toContain("BROWSE");
+ expect(tool?.description).toContain("file structure");
+ expect(tool?.description).toContain("tree");
+ expect(tool?.description).toContain("content");

- expect(tool?.description).toContain("MANAGE");
+ expect(tool?.description).toContain("Create, update, or upload");
+ expect(tool?.description).toContain("single");
+ expect(tool?.description).toContain("batch");

tests/unit/entities/mrs/registry.test.ts

# browse_merge_requests
- expect(tool!.description).toContain("BROWSE");
+ expect(tool!.description).toContain("merge requests");
  expect(tool!.description).toContain("list");
  expect(tool!.description).toContain("get");
  expect(tool!.description).toContain("diffs");
  expect(tool!.description).toContain("compare");

# browse_mr_discussions
- expect(tool!.description).toContain("BROWSE");
+ expect(tool!.description).toContain("discussion threads");
  expect(tool!.description).toContain("list");
  expect(tool!.description).toContain("drafts");
  expect(tool!.description).toContain("draft");

# manage_merge_request
- expect(tool!.description).toContain("MANAGE");
+ expect(tool!.description).toContain("merge requests");
  expect(tool!.description).toContain("create");
  expect(tool!.description).toContain("update");
  expect(tool!.description).toContain("merge");
  expect(tool!.description).toContain("approve");
  expect(tool!.description).toContain("unapprove");
  expect(tool!.description).toContain("get_approval_state");

# manage_mr_discussion
- expect(tool!.description).toContain("MANAGE");
+ expect(tool!.description).toContain("comments");  // or "threads"
  expect(tool!.description).toContain("comment");
  expect(tool!.description).toContain("thread");
  expect(tool!.description).toContain("reply");
  # ... actions stay the same

# manage_draft_notes
- expect(tool!.description).toContain("MANAGE");
+ expect(tool!.description).toContain("draft");
  expect(tool!.description).toContain("create");
  expect(tool!.description).toContain("publish");
  expect(tool!.description).toContain("delete");

tests/unit/entities/labels/registry.test.ts

- expect(tool?.description).toContain("BROWSE labels");
+ expect(tool?.description).toContain("labels");
  expect(tool?.description).toContain("list");
  expect(tool?.description).toContain("get");

- expect(tool?.description).toContain("MANAGE labels");
+ expect(tool?.description).toContain("labels");
  expect(tool?.description).toContain("create");
  expect(tool?.description).toContain("update");
  expect(tool?.description).toContain("delete");

tests/unit/entities/pipelines/registry.test.ts

- expect(tool?.description).toContain("BROWSE pipelines");
+ expect(tool?.description).toContain("CI/CD pipelines");
  expect(tool?.description).toContain("list");
  expect(tool?.description).toContain("get");
  expect(tool?.description).toContain("jobs");
  expect(tool?.description).toContain("triggers");
  expect(tool?.description).toContain("logs");

- expect(tool?.description).toContain("MANAGE pipelines");
+ expect(tool?.description).toContain("pipelines");
  expect(tool?.description).toContain("create");
  expect(tool?.description).toContain("retry");
  expect(tool?.description).toContain("cancel");

- expect(tool?.description).toContain("MANAGE pipeline jobs");
+ expect(tool?.description).toContain("individual CI/CD jobs");
  expect(tool?.description).toContain("play");
  expect(tool?.description).toContain("retry");
  expect(tool?.description).toContain("cancel");

tests/unit/entities/variables/registry.test.ts

- expect(tool?.description).toContain("BROWSE");
- expect(tool?.description).toContain("CI/CD variables");
+ expect(tool?.description).toContain("CI/CD variables");

- expect(tool?.description).toContain("MANAGE");
- expect(tool?.description).toContain("CI/CD variables");
+ expect(tool?.description).toContain("CI/CD variables");
+ expect(tool?.description).toContain("environment scoping");

tests/unit/entities/wiki/registry.test.ts

- expect(tool?.description).toContain("BROWSE wiki");
+ expect(tool?.description).toContain("wiki pages");
  expect(tool?.description).toContain("list");
  expect(tool?.description).toContain("get");

- expect(tool?.description).toContain("MANAGE wiki");
+ expect(tool?.description).toContain("wiki pages");
  expect(tool?.description).toContain("create");
  expect(tool?.description).toContain("update");
  expect(tool?.description).toContain("delete");

tests/unit/entities/releases/registry.test.ts

- expect(tool!.description).toContain("BROWSE");
+ expect(tool!.description).toContain("releases");
+ expect(tool!.description).toContain("assets");

- expect(tool!.description).toContain("MANAGE");
+ expect(tool!.description).toContain("releases");
+ expect(tool!.description).toContain("create");

tests/unit/entities/webhooks/registry.test.ts

- expect(tool!.description).toContain("BROWSE webhooks");
+ expect(tool!.description).toContain("webhook configurations");

- expect(tool!.description).toContain("Manage webhooks with full CRUD");
+ expect(tool!.description).toContain("webhooks");
+ expect(tool!.description).toContain("create");
+ expect(tool!.description).toContain("test");

tests/unit/entities/integrations/registry.test.ts

- expect(tool!.description).toContain("BROWSE project integrations");
+ expect(tool!.description).toContain("integrations");
+ expect(tool!.description).toContain("list");

- expect(tool!.description).toContain("MANAGE project integrations");
+ expect(tool!.description).toContain("integrations");
+ expect(tool!.description).toContain("update");
  expect(tool!.description).toContain("Slack");
  expect(tool!.description).toContain("Jira");
  expect(tool!.description).toContain("Discord");
  expect(tool!.description).toContain("gitlab-slack-application cannot be created via API");

tests/unit/entities/milestones/registry.test.ts

- expect(tool?.description).toContain("BROWSE milestones");
+ expect(tool?.description).toContain("milestone");
  expect(tool?.description).toContain("list");
  expect(tool?.description).toContain("get");
  expect(tool?.description).toContain("issues");
  expect(tool?.description).toContain("merge_requests");
  expect(tool?.description).toContain("burndown");

- expect(tool?.description).toContain("MANAGE milestones");
+ expect(tool?.description).toContain("milestone");
  expect(tool?.description).toContain("create");
  expect(tool?.description).toContain("update");
  expect(tool?.description).toContain("delete");
  expect(tool?.description).toContain("promote");

tests/unit/entities/milestones/index.test.ts

- expect(browseTool?.description).toContain("BROWSE");
+ expect(browseTool?.description).toContain("milestone");
- expect(manageTool?.description).toContain("MANAGE");
+ expect(manageTool?.description).toContain("milestone");

tests/unit/entities/workitems/registry.test.ts

- expect(tool?.description).toContain("BROWSE work items");
+ expect(tool?.description).toContain("work items");
  expect(tool?.description).toContain("list");
  expect(tool?.description).toContain("get");

- expect(tool?.description).toContain("MANAGE work items");
+ expect(tool?.description).toContain("work items");
  expect(tool?.description).toContain("create");
  expect(tool?.description).toContain("update");
  expect(tool?.description).toContain("delete");

tests/unit/entities/search/registry.test.ts

- expect(browseSearchTool?.description).toContain("SEARCH GitLab resources");
+ expect(browseSearchTool?.description).toContain("Search across GitLab");
  expect(browseSearchTool?.description).toContain("global");
  expect(browseSearchTool?.description).toContain("project");
  expect(browseSearchTool?.description).toContain("group");

tests/unit/entities/context/registry.test.ts

- expect(tool?.description).toContain("CONTEXT");
+ expect(tool?.description).toContain("session configuration");
+ expect(tool?.description).toContain("show");
+ expect(tool?.description).toContain("switch_preset");

New Tests Required

tests/unit/utils/description-utils.test.ts (new file)

describe("resolveRelatedReferences", () => {
  it("returns description unchanged when no Related section", () => {
    const desc = "Find projects. Actions: search, list, get.";
    expect(resolveRelatedReferences(desc, new Set(["manage_project"]))).toBe(desc);
  });

  it("keeps Related when referenced tool is available", () => {
    const desc = "Find projects. Related: manage_project to create.";
    const result = resolveRelatedReferences(desc, new Set(["manage_project"]));
    expect(result).toContain("Related: manage_project");
  });

  it("strips Related when referenced tool is unavailable", () => {
    const desc = "Find projects. Related: manage_project to create.";
    const result = resolveRelatedReferences(desc, new Set(["browse_labels"]));
    expect(result).toBe("Find projects.");
  });

  it("keeps only available tools from comma-separated list", () => {
    const desc = "Read discussions. Related: manage_mr_discussion to comment, manage_draft_notes to create.";
    const result = resolveRelatedReferences(desc, new Set(["manage_mr_discussion"]));
    expect(result).toBe("Read discussions. Related: manage_mr_discussion to comment.");
    expect(result).not.toContain("manage_draft_notes");
  });

  it("handles all tools unavailable in multi-reference", () => {
    const desc = "Monitor CI/CD. Related: manage_pipeline to retry, manage_pipeline_job for jobs.";
    const result = resolveRelatedReferences(desc, new Set(["browse_labels"]));
    expect(result).toBe("Monitor CI/CD.");
  });

  it("handles browse_ references correctly", () => {
    const desc = "Create refs. Related: browse_refs for inspection.";
    const result = resolveRelatedReferences(desc, new Set(["browse_refs"]));
    expect(result).toContain("browse_refs");
  });
});

tests/unit/registry-manager.test.ts (add to existing)

describe("dynamic Related resolution", () => {
  it("strips Related references when USE_* disables referenced tool", () => {
    // With USE_MRS=false, manage_merge_request is unavailable
    // browse_files description should NOT reference manage_files if USE_FILES=false
    // Test by checking description after cache build with specific flags
  });

  it("preserves Related when referenced tool is available", () => {
    // Default config: all tools enabled
    // browse_labels should contain "Related: manage_label"
  });

  it("strips Related when GITLAB_DENIED_TOOLS_REGEX matches referenced tool", () => {
    // GITLAB_DENIED_TOOLS_REGEX=manage_label
    // browse_labels should NOT contain "Related:"
  });

  it("strips Related in read-only mode for manage_ references", () => {
    // GITLAB_READ_ONLY_MODE=true
    // All "Related: manage_*" should be stripped
  });
});

Documentation Changes

1. Auto-generated: docs/TOOLS.md

No manual action. Regenerated by yarn list-tools --export --toc during semantic-release.

2. Manual: docs/public/llms.txt

Update descriptions to match new wording. Current descriptions are already reasonably aligned but should be refreshed after the description changes are implemented.

3. New section in docs/advanced/customization.md

Add after the "Dynamic Tool Descriptions" section:

## Dynamic Cross-References

Tool descriptions include "Related:" hints that reference complementary tools. These references are **automatically resolved at runtime** — if a referenced tool is disabled, the reference is stripped from the description.

### How It Works

When the tool cache is built, each description's "Related:" section is checked against available tools:

- If the referenced tool is enabled → reference appears in description
- If the referenced tool is disabled → reference is stripped
- If ALL references are disabled → entire "Related:" clause removed

### Example

With default configuration, `browse_labels` description includes:

List and inspect project or group labels. Actions: list, get. Related: manage_label to create/update/delete.


With `GITLAB_READ_ONLY_MODE=true` (all manage_* tools disabled):

List and inspect project or group labels. Actions: list, get.


### Why This Matters

AI agents receive tool descriptions via `list_tools`. Dead references to unavailable tools:
- Waste context tokens
- Confuse routing (agent tries to call unavailable tool)
- Create poor user experience (agent suggests actions that fail)

Dynamic resolution ensures descriptions always reflect the actual tool surface available to the agent.

### Interaction with Custom Descriptions

Custom descriptions set via `GITLAB_TOOL_*` environment variables **override the entire description** including any "Related:" section. Dynamic resolution only applies to default (built-in) descriptions.

File Change Summary

File Change Type
src/utils/description-utils.ts New fileresolveRelatedReferences()
src/registry-manager.ts Add second pass calling resolveRelatedReferences()
src/entities/files/registry.ts Update 2 descriptions
src/entities/mrs/registry.ts Update 5 descriptions
src/entities/labels/registry.ts Update 2 descriptions
src/entities/pipelines/registry.ts Update 3 descriptions
src/entities/snippets/registry.ts Update 2 descriptions
src/entities/variables/registry.ts Update 2 descriptions
src/entities/wiki/registry.ts Update 2 descriptions
src/entities/releases/registry.ts Update 2 descriptions
src/entities/refs/registry.ts Update 2 descriptions
src/entities/members/registry.ts Update 2 descriptions
src/entities/milestones/registry.ts Update 2 descriptions
src/entities/integrations/registry.ts Update 2 descriptions
src/entities/webhooks/registry.ts Update 2 descriptions
src/entities/workitems/registry.ts Update 2 descriptions
src/entities/search/registry.ts Update 1 description
src/entities/context/registry.ts Update 1 description
tests/unit/utils/description-utils.test.ts New file — unit tests for resolver
tests/unit/entities/files/registry.test.ts Update assertions
tests/unit/entities/mrs/registry.test.ts Update assertions
tests/unit/entities/labels/registry.test.ts Update assertions
tests/unit/entities/pipelines/registry.test.ts Update assertions
tests/unit/entities/variables/registry.test.ts Update assertions
tests/unit/entities/wiki/registry.test.ts Update assertions
tests/unit/entities/releases/registry.test.ts Update assertions
tests/unit/entities/webhooks/registry.test.ts Update assertions
tests/unit/entities/integrations/registry.test.ts Update assertions
tests/unit/entities/milestones/registry.test.ts Update assertions
tests/unit/entities/milestones/index.test.ts Update assertions
tests/unit/entities/workitems/registry.test.ts Update assertions
tests/unit/entities/search/registry.test.ts Update assertions
tests/unit/entities/context/registry.test.ts Update assertions
tests/unit/entities/members/registry.test.ts Add description assertions
tests/unit/entities/snippets/registry.test.ts Add description assertions
tests/unit/entities/refs/registry.test.ts Add description assertions
tests/unit/registry-manager.test.ts Add Related resolution tests
docs/advanced/customization.md Add "Dynamic Cross-References" section
docs/public/llms.txt Refresh descriptions

Semver Impact

MINOR version bump (feat:):

  • No tools renamed or removed
  • No breaking schema changes
  • Description text changes are non-breaking (informational only)
  • New runtime behavior (Related stripping) is additive

Acceptance Criteria

  • All 44 tools use intent-first descriptions (zero UPPERCASE PREFIX remaining)
  • All descriptions include Related: where disambiguation is valuable
  • resolveRelatedReferences() strips dead references when tools are gated
  • GITLAB_READ_ONLY_MODE=true strips all Related: manage_* references
  • GITLAB_DENIED_TOOLS_REGEX strips matching Related references
  • Unit tests for resolveRelatedReferences() pass (6+ cases)
  • Registry manager integration tests for dynamic resolution pass
  • All existing description assertions updated and passing
  • docs/advanced/customization.md documents the behavior
  • docs/public/llms.txt refreshed with new wording
  • yarn lint passes
  • yarn test passes (unit tests)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature, new MCP tool, new capabilityreleased

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions