Skip to content

Commit 065e53b

Browse files
authored
feat(descriptions): intent-first tool descriptions with dynamic Related resolution (#172)
Rewrite all 32 tool descriptions from UPPERCASE PREFIX format to intent-first agentic format with dynamic cross-references. - New resolveRelatedReferences() utility in src/utils/description-utils.ts - Dynamic Related resolution in registry-manager.ts buildToolLookupCache() and getAllToolDefinitionsTierless() — strips unavailable tool references - Updated all 18 entity registries with intent-first descriptions - Unit tests for description-utils (10 cases) - RegistryManager tests for Related resolution (5 scenarios) - Updated assertions in 14 entity test files - New Dynamic Cross-References section in docs/advanced/customization.md Closes #169
1 parent c486056 commit 065e53b

File tree

36 files changed

+406
-80
lines changed

36 files changed

+406
-80
lines changed

docs/advanced/customization.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,30 @@ export GITLAB_TOOL_MANAGE_WORK_ITEM="Create and manage tickets for our sprint pl
4646
- Tool names in variables must be UPPERCASE
4747
- Invalid tool names are ignored with a debug warning
4848

49+
## Dynamic Cross-References
50+
51+
Tool descriptions include `Related:` sections that reference companion tools (e.g., browse→manage pairs). These references are resolved dynamically at startup — if a referenced tool is unavailable (disabled via `USE_*`, `GITLAB_DENIED_TOOLS_REGEX`, read-only mode, or tier/version gating), it is automatically stripped from the description.
52+
53+
### How It Works
54+
55+
```
56+
# Source description (in registry):
57+
"List labels. Related: manage_label to create/update/delete."
58+
59+
# If manage_label is disabled (USE_LABELS_MANAGE=false or read-only mode):
60+
"List labels."
61+
62+
# If manage_label is available:
63+
"List labels. Related: manage_label to create/update/delete."
64+
```
65+
66+
### Notes
67+
68+
- References are identified by `browse_*` or `manage_*` prefixes in the `Related:` section
69+
- Multiple comma-separated references are resolved individually — only unavailable ones are stripped
70+
- If all referenced tools are unavailable, the entire `Related:` clause is removed
71+
- Custom description overrides (`GITLAB_TOOL_*`) bypass resolution entirely — you control the full text
72+
4973
## Fine-Grained Action Filtering
5074

5175
For CQRS tools, disable specific actions while keeping others available. This reduces AI context token usage by removing disabled actions and their exclusive parameters from the schema.

docs/public/llms.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ Optional: GITLAB_API_URL (defaults to https://gitlab.com)
108108
- Tool filtering: GITLAB_DENIED_TOOLS_REGEX to disable specific tools
109109
- Action filtering: GITLAB_DENIED_ACTIONS to block specific actions
110110
- Project scoping: GITLAB_ALLOWED_PROJECT_IDS to restrict access
111+
- Dynamic cross-references: Related tool hints auto-stripped when referenced tools are disabled
111112

112113
# Feature Flags (USE_* environment variables)
113114

src/entities/context/registry.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,7 @@ export const contextToolRegistry: ToolRegistry = new Map<string, EnhancedToolDef
2727
{
2828
name: "manage_context",
2929
description:
30-
"CONTEXT: Manage runtime session context. Actions: " +
31-
"'show' returns current context (host, preset, scope, mode); " +
32-
"'list_presets' lists available presets with descriptions; " +
33-
"'list_profiles' lists OAuth profiles (OAuth mode only); " +
34-
"'switch_preset' changes active preset by name; " +
35-
"'switch_profile' changes OAuth profile (OAuth mode only); " +
36-
"'set_scope' restricts operations to a namespace (auto-detects group vs project); " +
37-
"'reset' restores initial context from session start.",
30+
"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).",
3831
inputSchema: z.toJSONSchema(ManageContextSchema),
3932
// No gate - context management is always available
4033
handler: async (args: unknown) => {

src/entities/files/registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const filesToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefin
2323
{
2424
name: "browse_files",
2525
description:
26-
'BROWSE repository files. Actions: "tree" lists files/folders with pagination, "content" reads file contents. Use for exploring project structure or reading source code.',
26+
"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.",
2727
inputSchema: z.toJSONSchema(BrowseFilesSchema),
2828
gate: { envVar: "USE_FILES", defaultValue: true },
2929
handler: async (args: unknown) => {
@@ -105,7 +105,7 @@ export const filesToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefin
105105
{
106106
name: "manage_files",
107107
description:
108-
'MANAGE repository files. Actions: "single" creates/updates one file, "batch" commits multiple files atomically, "upload" adds markdown attachments.',
108+
"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.",
109109
inputSchema: z.toJSONSchema(ManageFilesSchema),
110110
gate: { envVar: "USE_FILES", defaultValue: true },
111111
handler: async (args: unknown) => {

src/entities/integrations/registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const integrationsToolRegistry: ToolRegistry = new Map<string, EnhancedTo
2222
{
2323
name: "browse_integrations",
2424
description:
25-
'BROWSE project integrations. Actions: "list" shows all active integrations (Slack, Jira, Discord, Teams, Jenkins, etc.), "get" retrieves settings for a specific integration by type slug.',
25+
"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.",
2626
inputSchema: z.toJSONSchema(BrowseIntegrationsSchema, {}),
2727
gate: { envVar: "USE_INTEGRATIONS", defaultValue: true },
2828
handler: async (args: unknown) => {
@@ -72,7 +72,7 @@ export const integrationsToolRegistry: ToolRegistry = new Map<string, EnhancedTo
7272
{
7373
name: "manage_integration",
7474
description:
75-
'MANAGE project integrations. Actions: "update" modifies or enables integration with specific config, "disable" removes integration. Supports 50+ integrations: Slack, Jira, Discord, Teams, Jenkins, etc. Note: gitlab-slack-application cannot be created via API - requires OAuth install from UI.',
75+
"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.",
7676
inputSchema: z.toJSONSchema(ManageIntegrationSchema, {}),
7777
gate: { envVar: "USE_INTEGRATIONS", defaultValue: true },
7878
handler: async (args: unknown) => {

src/entities/labels/registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const labelsToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefi
2222
{
2323
name: "browse_labels",
2424
description:
25-
'BROWSE labels. Actions: "list" shows all labels in project/group with filtering, "get" retrieves single label details by ID or name.',
25+
"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.",
2626
inputSchema: z.toJSONSchema(BrowseLabelsSchema),
2727
gate: { envVar: "USE_LABELS", defaultValue: true },
2828
handler: async (args: unknown) => {
@@ -73,7 +73,7 @@ export const labelsToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefi
7373
{
7474
name: "manage_label",
7575
description:
76-
'MANAGE labels. Actions: "create" adds new label (requires name and color), "update" modifies existing label, "delete" removes label permanently.',
76+
"Create, update, or delete project/group labels. Actions: create (name + hex color required), update (modify properties), delete (remove permanently). Related: browse_labels for discovery.",
7777
inputSchema: z.toJSONSchema(ManageLabelSchema),
7878
gate: { envVar: "USE_LABELS", defaultValue: true },
7979
handler: async (args: unknown) => {

src/entities/members/registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const membersToolRegistry: ToolRegistry = new Map<string, EnhancedToolDef
2222
{
2323
name: "browse_members",
2424
description:
25-
'BROWSE team members in projects and groups. Actions: "list_project" lists project members, "list_group" lists group members, "get_project" gets project member details, "get_group" gets group member details, "list_all_project" includes inherited members, "list_all_group" includes inherited members. Access levels: 0=No access, 5=Minimal, 10=Guest, 20=Reporter, 30=Developer, 40=Maintainer, 50=Owner.',
25+
"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.",
2626
inputSchema: z.toJSONSchema(BrowseMembersSchema),
2727
handler: async (args: unknown): Promise<unknown> => {
2828
const input = BrowseMembersSchema.parse(args);
@@ -101,7 +101,7 @@ export const membersToolRegistry: ToolRegistry = new Map<string, EnhancedToolDef
101101
{
102102
name: "manage_member",
103103
description:
104-
'MANAGE team members in projects and groups. Actions: "add_to_project" adds member to project, "add_to_group" adds member to group, "remove_from_project" removes from project, "remove_from_group" removes from group, "update_project" changes project member access level, "update_group" changes group member access level. Access levels: 0=No access, 5=Minimal, 10=Guest, 20=Reporter, 30=Developer, 40=Maintainer, 50=Owner.',
104+
"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.",
105105
inputSchema: z.toJSONSchema(ManageMemberSchema),
106106
handler: async (args: unknown): Promise<unknown> => {
107107
const input = ManageMemberSchema.parse(args);

src/entities/milestones/registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const milestonesToolRegistry: ToolRegistry = new Map<string, EnhancedTool
2323
{
2424
name: "browse_milestones",
2525
description:
26-
'BROWSE milestones. Actions: "list" shows milestones with filtering, "get" retrieves single milestone, "issues" lists issues in milestone, "merge_requests" lists MRs in milestone, "burndown" gets burndown chart data.',
26+
"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.",
2727
inputSchema: z.toJSONSchema(BrowseMilestonesSchema),
2828
gate: { envVar: "USE_MILESTONE", defaultValue: true },
2929
handler: async (args: unknown) => {
@@ -98,7 +98,7 @@ export const milestonesToolRegistry: ToolRegistry = new Map<string, EnhancedTool
9898
{
9999
name: "manage_milestone",
100100
description:
101-
'MANAGE milestones. Actions: "create" creates new milestone, "update" modifies existing milestone, "delete" removes milestone, "promote" elevates project milestone to group level.',
101+
"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.",
102102
inputSchema: z.toJSONSchema(ManageMilestoneSchema),
103103
gate: { envVar: "USE_MILESTONE", defaultValue: true },
104104
handler: async (args: unknown) => {

src/entities/mrs/registry.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const mrsToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefinit
6767
{
6868
name: "browse_merge_requests",
6969
description:
70-
'BROWSE merge requests. Actions: "list" shows MRs with filtering, "get" retrieves single MR by IID or branch, "diffs" shows file changes, "compare" diffs two branches/commits.',
70+
"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.",
7171
inputSchema: z.toJSONSchema(BrowseMergeRequestsSchema),
7272
gate: { envVar: "USE_MRS", defaultValue: true },
7373
handler: async (args: unknown) => {
@@ -172,7 +172,7 @@ export const mrsToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefinit
172172
{
173173
name: "browse_mr_discussions",
174174
description:
175-
'BROWSE MR discussions and draft notes. Actions: "list" shows all discussion threads, "drafts" lists unpublished draft notes, "draft" gets single draft note.',
175+
"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.",
176176
inputSchema: z.toJSONSchema(BrowseMrDiscussionsSchema),
177177
gate: { envVar: "USE_MRS", defaultValue: true },
178178
handler: async (args: unknown) => {
@@ -228,7 +228,7 @@ export const mrsToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefinit
228228
{
229229
name: "manage_merge_request",
230230
description:
231-
'MANAGE merge requests. Actions: "create" creates new MR, "update" modifies existing MR, "merge" merges approved MR into target branch, "approve" approves MR, "unapprove" removes approval, "get_approval_state" gets approval status.',
231+
"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.",
232232
inputSchema: z.toJSONSchema(ManageMergeRequestSchema),
233233
gate: { envVar: "USE_MRS", defaultValue: true },
234234
handler: async (args: unknown) => {
@@ -338,7 +338,7 @@ export const mrsToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefinit
338338
{
339339
name: "manage_mr_discussion",
340340
description:
341-
'MANAGE MR discussions. Actions: "comment" adds comment, "thread" starts discussion, "reply" responds to thread, "update" modifies note, "apply_suggestion" applies code suggestion, "apply_suggestions" batch applies suggestions, "resolve" resolves/unresolves thread, "suggest" creates code suggestion.',
341+
"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.",
342342
inputSchema: z.toJSONSchema(ManageMrDiscussionSchema),
343343
gate: { envVar: "USE_MRS", defaultValue: true },
344344
handler: async (args: unknown) => {
@@ -509,7 +509,7 @@ export const mrsToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefinit
509509
{
510510
name: "manage_draft_notes",
511511
description:
512-
'MANAGE draft notes. Actions: "create" creates draft note, "update" modifies draft, "publish" publishes single draft, "publish_all" publishes all drafts, "delete" removes draft.',
512+
"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.",
513513
inputSchema: z.toJSONSchema(ManageDraftNotesSchema),
514514
gate: { envVar: "USE_MRS", defaultValue: true },
515515
handler: async (args: unknown) => {

src/entities/pipelines/registry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const pipelinesToolRegistry: ToolRegistry = new Map<string, EnhancedToolD
2525
{
2626
name: "browse_pipelines",
2727
description:
28-
'BROWSE pipelines. Actions: "list" searches pipelines with filtering, "get" retrieves single pipeline details, "jobs" lists jobs in pipeline, "triggers" lists bridge/trigger jobs, "job" gets single job details, "logs" fetches job console output.',
28+
"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.",
2929
inputSchema: z.toJSONSchema(BrowsePipelinesSchema),
3030
gate: { envVar: "USE_PIPELINE", defaultValue: true },
3131
handler: async (args: unknown): Promise<unknown> => {
@@ -173,7 +173,7 @@ export const pipelinesToolRegistry: ToolRegistry = new Map<string, EnhancedToolD
173173
{
174174
name: "manage_pipeline",
175175
description:
176-
'MANAGE pipelines. Actions: "create" triggers new pipeline on branch/tag with optional variables, "retry" re-runs failed/canceled pipeline, "cancel" stops running pipeline.',
176+
"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.",
177177
inputSchema: z.toJSONSchema(ManagePipelineSchema),
178178
gate: { envVar: "USE_PIPELINE", defaultValue: true },
179179
handler: async (args: unknown): Promise<unknown> => {
@@ -291,7 +291,7 @@ export const pipelinesToolRegistry: ToolRegistry = new Map<string, EnhancedToolD
291291
{
292292
name: "manage_pipeline_job",
293293
description:
294-
'MANAGE pipeline jobs. Actions: "play" triggers manual job with optional variables, "retry" re-runs failed/canceled job, "cancel" stops running job.',
294+
"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.",
295295
inputSchema: z.toJSONSchema(ManagePipelineJobSchema),
296296
gate: { envVar: "USE_PIPELINE", defaultValue: true },
297297
handler: async (args: unknown): Promise<unknown> => {

0 commit comments

Comments
 (0)