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).
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
-
.append_tool_table(lines, heading, entries)
Appends a category tool table to the lines array.
-
.build_tool_index ⇒ Hash{String => Hash}
Builds an index of tool name to entry hash from Governance.
-
.format_tool_row(entry) ⇒ String
Formats a single tool entry as a markdown table row.
-
.generate ⇒ String
Generates the complete instructions markdown string.
-
.header_section ⇒ String
Header section.
-
.mutation_safety_section ⇒ String
Documents mutation safety rules.
-
.resource_section ⇒ String
Generates the resource URI documentation.
-
.scope_hierarchy_section ⇒ String
Explains the scope hierarchy for rule resolution.
-
.tool_entries_for(tool_names) ⇒ Array<Hash>
Builds tool entries for a list of tool names from Governance.
-
.tool_inventory_section ⇒ String
Generates the tool inventory grouped by category.
-
.uncategorized_tools ⇒ Array<Hash>
Returns tool entries not assigned to any category.
-
.workflow_section ⇒ String
Documents common workflows.
Class Method Details
.append_tool_table(lines, heading, entries)
This method returns an undefined value.
Appends a category tool table to the lines array.
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_index ⇒ Hash{String => Hash}
Builds an index of tool name to entry hash from Governance.
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.
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 |
.generate ⇒ String
Generates the complete instructions markdown string.
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_section ⇒ String
Returns 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_section ⇒ String
Documents mutation safety rules.
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_section ⇒ String
Generates the resource URI documentation.
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_section ⇒ String
Explains the scope hierarchy for rule resolution.
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.
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_section ⇒ String
Generates the tool inventory grouped by category.
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_tools ⇒ Array<Hash>
Returns tool entries not assigned to any category.
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_section ⇒ String
Documents common workflows.
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 |