Module: RosettAi::Mcp::Instructions

Defined in:
lib/rosett_ai/mcp/instructions.rb

Overview

Generates the MCP server instructions markdown for AI client auto-discovery. The instructions field is read by AI clients on session start to understand available tools, resources, and workflows without manual lookup.

Content is generated dynamically from the registered tool and resource classes in Governance, ensuring documentation-tool parity (DES-RAI-MCP-002 constraint).

Author:

  • hugo

  • claude

Constant Summary collapse

CATEGORIES =

Tool categories for the instructions inventory. Maps category name to the tool class constants that belong to it.

{
  'Discovery' => [
    'rai_behaviour_list', 'rai_behaviour_show', 'rai_behaviour_display',
    'rai_design_list', 'rai_design_show', 'rai_documentation_status',
    'rai_rule_search', 'rai_schema_get', 'rai_compile_status'
  ],
  'Enforcement' => [
    'rai_hook_preview', 'rai_hook_install', 'rai_context_query'
  ],
  'Management' => [
    'rai_behaviour_manage', 'rai_compile', 'rai_config_compile',
    'rai_validate', 'rai_init', 'rai_backup', 'rai_content', 'rai_retrofit'
  ],
  'Compliance' => [
    'rai_comply', 'rai_provenance', 'rai_provenance_init', 'rai_adopt', 'rai_tooling'
  ],
  'Operations' => [
    'rai_doctor', 'rai_project', 'rosett_ai_engines',
    'rai_hooks_status', 'rai_config_status', 'rai_license_status'
  ],
  'Workflow' => [
    'rai_workflow', 'rai_workflow_execute'
  ]
}.freeze
RESOURCE_URIS =

Resource URI prefixes for the instructions inventory.

{
  'rosett-ai://behaviour/{name}' => 'Behaviour YAML via 3-tier lookup (supports ?tier=xdg)',
  'rosett-ai://design/{name}' => 'Design document YAML content',
  'rosett-ai://provenance/' => 'AI provenance entries',
  'rosett-ai://config/{scope}' => 'Settings for a scope (managed, user, project, local)',
  'rosett-ai://schema/{name}' => 'JSON Schema content for validation',
  'rosett-ai://rules/{name}' => 'Compiled rule markdown content',
  'rosett-ai://hooks/{scope}' => 'Installed enforcement hook scripts'
}.freeze

Class Method Summary collapse

Class Method Details

.append_tool_table(lines, heading, entries)

This method returns an undefined value.

Appends a category tool table to the lines array.

Parameters:

  • lines (Array<String>)

    accumulator

  • heading (String)

    category heading

  • entries (Array<Hash>)

    tool entries



110
111
112
113
114
115
116
# File 'lib/rosett_ai/mcp/instructions.rb', line 110

def append_tool_table(lines, heading, entries)
  lines << "### #{heading}\n"
  lines << '| Tool | Description | Read-only |'
  lines << '|------|-------------|-----------|'
  entries.each { |e| lines << format_tool_row(e) }
  lines << ''
end

.build_tool_indexHash{String => Hash}

Builds an index of tool name to entry hash from Governance.

Returns:

  • (Hash{String => Hash})

    tool name to entry mapping



254
255
256
257
258
259
260
261
262
263
# File 'lib/rosett_ai/mcp/instructions.rb', line 254

def build_tool_index
  Governance::TOOL_CLASSES.each_with_object({}) do |klass, index|
    name = klass::TOOL_NAME
    index[name] = {
      name: name,
      description: klass::DESCRIPTION,
      read_only: klass::ANNOTATIONS['readOnlyHint'] == true
    }
  end
end

.format_tool_row(entry) ⇒ String

Formats a single tool entry as a markdown table row.

Parameters:

  • entry (Hash)

    tool entry with :name, :description, :read_only

Returns:

  • (String)

    markdown table row



122
123
124
125
# File 'lib/rosett_ai/mcp/instructions.rb', line 122

def format_tool_row(entry)
  ro = entry[:read_only] ? 'Yes' : 'No'
  "| `#{entry[:name]}` | #{entry[:description]} | #{ro} |"
end

.generateString

Generates the complete instructions markdown string.

Returns:

  • (String)

    markdown instructions for AI client consumption



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rosett_ai/mcp/instructions.rb', line 63

def generate
  sections = [
    header_section,
    tool_inventory_section,
    resource_section,
    scope_hierarchy_section,
    workflow_section,
    mutation_safety_section
  ]
  sections.join("\n\n")
end

.header_sectionString

Returns header section.

Returns:

  • (String)

    header section



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rosett_ai/mcp/instructions.rb', line 76

def header_section
  <<~MARKDOWN.chomp
    # Rosett-AI MCP Server

    This server exposes rosett-ai configuration management tools via the
    Model Context Protocol. Use this guide to select the right tool for
    your task.

    Version: #{RosettAi::VERSION}
  MARKDOWN
end

.mutation_safety_sectionString

Documents mutation safety rules.

Returns:

  • (String)

    mutation safety markdown



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/rosett_ai/mcp/instructions.rb', line 212

def mutation_safety_section
  <<~MARKDOWN.chomp
    ## Mutation Safety

    Tools marked as **not read-only** perform writes. Before calling
    mutation tools:

    1. Present the action to the user and ask for confirmation
    2. Prefer `simulate: true` first (where supported) to preview changes
    3. The server does not enforce confirmation — the AI client must

    Mutation tools: `rai_compile`, `rai_config_compile`, `rai_behaviour_manage`,
    `rai_init`, `rai_backup`, `rai_content`, `rai_retrofit`,
    `rai_provenance_init`, `rai_workflow_execute`, `rai_hook_install`.

    `rai_hook_install` requires `confirm: true` and auto-backs up
    existing hooks before writing. Use `rai_hook_preview` first.
  MARKDOWN
end

.resource_sectionString

Generates the resource URI documentation.

Returns:

  • (String)

    resource section markdown



130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rosett_ai/mcp/instructions.rb', line 130

def resource_section
  table_rows = RESOURCE_URIS.map { |uri, desc| "| `#{uri}` | #{desc} |" }

  [
    "## Resources\n",
    '| URI Pattern | Description |',
    '|-------------|-------------|',
    *table_rows,
    '',
    'Query parameters:',
    '- `?tier=project|xdg|packaged` — request a specific tier (bypasses merge)',
    '- `?strategy=first_wins|deep_merge|array_union` — override merge strategy'
  ].join("\n")
end

.scope_hierarchy_sectionString

Explains the scope hierarchy for rule resolution.

Returns:

  • (String)

    scope hierarchy markdown



148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/rosett_ai/mcp/instructions.rb', line 148

def scope_hierarchy_section
  <<~MARKDOWN.chomp
    ## Scope Hierarchy

    Rules are resolved in priority order (highest scope wins):

    1. **Project** (`.rosett-ai/conf/behaviour/`) — project-specific overrides
    2. **XDG user** (`~/.config/rosett-ai/conf/behaviour/`) — user-authored global rules
    3. **Packaged** (`/opt/rosett-ai/app/conf/behaviour/`) — default templates from installation

    Compiled output goes to `~/.claude/rules/` via `rai_compile`.
  MARKDOWN
end

.tool_entries_for(tool_names) ⇒ Array<Hash>

Builds tool entries for a list of tool names from Governance.

Parameters:

  • tool_names (Array<String>)

    tool names to look up

Returns:

  • (Array<Hash>)

    tool entry hashes with :name, :description, :read_only



236
237
238
239
# File 'lib/rosett_ai/mcp/instructions.rb', line 236

def tool_entries_for(tool_names)
  tool_index = build_tool_index
  tool_names.filter_map { |name| tool_index[name] }
end

.tool_inventory_sectionString

Generates the tool inventory grouped by category.

Returns:

  • (String)

    tool inventory markdown



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rosett_ai/mcp/instructions.rb', line 91

def tool_inventory_section
  lines = ["## Tool Inventory\n"]

  CATEGORIES.each do |category, tool_names|
    append_tool_table(lines, category, tool_entries_for(tool_names))
  end

  uncategorized = uncategorized_tools
  append_tool_table(lines, 'Other', uncategorized) unless uncategorized.empty?

  lines.join("\n")
end

.uncategorized_toolsArray<Hash>

Returns tool entries not assigned to any category.

Returns:

  • (Array<Hash>)

    uncategorized tool entries



244
245
246
247
248
249
# File 'lib/rosett_ai/mcp/instructions.rb', line 244

def uncategorized_tools
  all_categorized = CATEGORIES.values.flatten
  tool_index = build_tool_index
  tool_index.except(*all_categorized)
    .values
end

.workflow_sectionString

Documents common workflows.

Returns:

  • (String)

    workflow section markdown



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/rosett_ai/mcp/instructions.rb', line 165

def workflow_section
  <<~MARKDOWN.chomp
    ## Common Workflows

    ### List and inspect behaviours

    1. `rai_behaviour_list` — see all available behaviours
    2. `rai_behaviour_show(name: "criticalthinking")` — inspect rules
    3. Read `rosett-ai://behaviour/criticalthinking` — raw YAML content

    ### Search and query rules

    1. `rai_rule_search(keyword: "TMPDIR")` — find rules by keyword
    2. `rai_context_query(tool_name: "Bash")` — what rules apply?
    3. `rai_schema_get(schema_name: "behaviour")` — get validation schema

    ### Compile rules for an AI engine

    1. `rai_validate` — check all config files are valid
    2. `rai_compile(engine: "claude", simulate: true)` — preview output
    3. `rai_compile(engine: "claude")` — compile to `~/.claude/rules/`
    4. `rai_compile_status` — check what needs recompilation

    ### Install enforcement hooks

    Rules with an `enforcement` block (type: enforceable, pattern, applies_to,
    action) can be compiled into Claude Code PreToolUse hooks:

    1. `rai_hook_preview(behaviour_name: "X")` — preview hook script
    2. Review the output — check which rules are enforceable vs downgraded
    3. `rai_hook_install(behaviour_name: "X", confirm: true)` — install

    The enforcement pipeline validates patterns (rejects degenerate patterns
    like `.*`), generates self-contained Ruby scripts, and installs them as
    PreToolUse hooks. Invalid enforceable rules are downgraded to advisory.

    ### Check project health

    1. `rai_doctor` — run diagnostic checks
    2. `rai_comply` — CRA, license, and SPDX header compliance
    3. `rai_config_status` — configuration scope status
  MARKDOWN
end