rosett-ai 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (527) hide show
  1. checksums.yaml +7 -0
  2. data/.ai-provenance.yml +119 -0
  3. data/.debride_whitelist +186 -0
  4. data/.fasterer.yml +29 -0
  5. data/.mdl_style.rb +10 -0
  6. data/.mdlrc +3 -0
  7. data/.mutant.yml +49 -0
  8. data/.namespace-allowlist +42 -0
  9. data/.reek.yml +1040 -0
  10. data/.rosett-ai/config.yml +3 -0
  11. data/.rspec +5 -0
  12. data/.rubocop.yml +380 -0
  13. data/.ruby-version +1 -0
  14. data/.yamllint +51 -0
  15. data/.yardopts +12 -0
  16. data/AI-DISCLOSURE.md +48 -0
  17. data/CHANGELOG.md +519 -0
  18. data/CLAUDE.md +141 -0
  19. data/CONTRIBUTING.md +734 -0
  20. data/INSTALL.md +154 -0
  21. data/LICENSE +674 -0
  22. data/LICENSE.md +675 -0
  23. data/QUICKSTART.md +73 -0
  24. data/README.md +366 -0
  25. data/Rakefile +200 -0
  26. data/SECURITY.md +114 -0
  27. data/bin/rai +1 -0
  28. data/cliff.toml +52 -0
  29. data/conf/adopt_redactions.yml +8 -0
  30. data/conf/behaviour/.gitkeep +0 -0
  31. data/conf/compliance/cra_rules.yml +25 -0
  32. data/conf/compliance/license_rules.yml +20 -0
  33. data/conf/design/aaif_alignment.yml +181 -0
  34. data/conf/design/ab_testing.yml +172 -0
  35. data/conf/design/accessibility.yml +84 -0
  36. data/conf/design/ai_authorship.yml +210 -0
  37. data/conf/design/ai_provenance.yml +224 -0
  38. data/conf/design/ai_tool_configuration.yml +207 -0
  39. data/conf/design/architecture.yml +139 -0
  40. data/conf/design/autocompletion.yml +115 -0
  41. data/conf/design/backward_compatibility.yml +112 -0
  42. data/conf/design/behaviour_composition.yml +246 -0
  43. data/conf/design/build_rake_extraction.yml +57 -0
  44. data/conf/design/ci_pipeline.yml +100 -0
  45. data/conf/design/claude_code_configuration.yml +157 -0
  46. data/conf/design/compiler.yml +128 -0
  47. data/conf/design/comply.yml +153 -0
  48. data/conf/design/content_packs.yml +84 -0
  49. data/conf/design/desktop_integration.yml +289 -0
  50. data/conf/design/distribution.yml +216 -0
  51. data/conf/design/doctor.yml +184 -0
  52. data/conf/design/documentation.yml +152 -0
  53. data/conf/design/engine_architecture.yml +257 -0
  54. data/conf/design/error_handling.yml +103 -0
  55. data/conf/design/feature_flags.yml +142 -0
  56. data/conf/design/git_hooks.yml +165 -0
  57. data/conf/design/gui_plugins.yml +475 -0
  58. data/conf/design/i18n.yml +84 -0
  59. data/conf/design/integration_testing.yml +56 -0
  60. data/conf/design/licensing_system.yml +88 -0
  61. data/conf/design/lifecycle_management.yml +208 -0
  62. data/conf/design/mcp_integration.yml +207 -0
  63. data/conf/design/mcp_settings.yml +126 -0
  64. data/conf/design/migration.yml +56 -0
  65. data/conf/design/monitoring_observability.yml +194 -0
  66. data/conf/design/namespace_cleanup.yml +145 -0
  67. data/conf/design/plugin_test_segregation.yml +145 -0
  68. data/conf/design/policy_management.yml +229 -0
  69. data/conf/design/project_management.yml +183 -0
  70. data/conf/design/rai_mcp_asset_discovery.yml +164 -0
  71. data/conf/design/rai_mcp_server.yml +605 -0
  72. data/conf/design/release_management.yml +117 -0
  73. data/conf/design/retrofit.yml +199 -0
  74. data/conf/design/retrospective_analyzer.yml +79 -0
  75. data/conf/design/scope_hierarchy.yml +352 -0
  76. data/conf/design/security.yml +115 -0
  77. data/conf/design/session_retrospective.yml +85 -0
  78. data/conf/design/smart_ui_feedback.yml +89 -0
  79. data/conf/design/structured_logging.yml +148 -0
  80. data/conf/design/styles.yml +123 -0
  81. data/conf/design/test_peer_review.yml +89 -0
  82. data/conf/design/testing.yml +136 -0
  83. data/conf/design/threat_model.yml +108 -0
  84. data/conf/design/ui_framework.yml +111 -0
  85. data/conf/design/usage_optimization.yml +122 -0
  86. data/conf/design/version_management.yml +60 -0
  87. data/conf/design/workflow.yml +227 -0
  88. data/conf/mcp/server_defaults.yml +42 -0
  89. data/conf/mcp/trust.yml +21 -0
  90. data/conf/packaging/core.yml +12 -0
  91. data/conf/packaging/gtk4.yml +11 -0
  92. data/conf/packaging/qt6.yml +11 -0
  93. data/conf/policy/default_deny_list.yml +197 -0
  94. data/conf/review/cli-command-audit.yml +857 -0
  95. data/conf/review/design-docs.yml +1064 -0
  96. data/conf/review/design-questionnaire.yml +153 -0
  97. data/conf/review/questionnaire.yml +146 -0
  98. data/conf/review/rosett-ai-core.yml +2919 -0
  99. data/conf/schemas/ai_config_schema.json +73 -0
  100. data/conf/schemas/behaviour_schema.json +132 -0
  101. data/conf/schemas/compliance_rule_schema.json +63 -0
  102. data/conf/schemas/content_pack_manifest_schema.json +51 -0
  103. data/conf/schemas/design_schema.json +210 -0
  104. data/conf/schemas/engine_manifest_schema.json +144 -0
  105. data/conf/schemas/lockfile_schema.json +74 -0
  106. data/conf/schemas/mcp_server_schema.json +48 -0
  107. data/conf/schemas/packaging_schema.json +70 -0
  108. data/conf/schemas/policy_schema.json +85 -0
  109. data/conf/schemas/provenance_schema.json +84 -0
  110. data/conf/schemas/rai_config_schema.json +56 -0
  111. data/conf/schemas/rai_project_schema.json +20 -0
  112. data/conf/schemas/scope_hierarchy_schema.json +49 -0
  113. data/conf/schemas/target_schema.json +67 -0
  114. data/conf/schemas/tooling_schema.json +65 -0
  115. data/conf/schemas/workflow_schema.json +112 -0
  116. data/conf/targets/agents_md.yml +17 -0
  117. data/conf/targets/claude.yml +12 -0
  118. data/conf/tooling/tools.yml +58 -0
  119. data/dist/rosett-ai-mcp.service +48 -0
  120. data/dist/rosett-ai-mcp.yml.default +45 -0
  121. data/doc/AAIF_POSITIONING.md +58 -0
  122. data/doc/ADOPT.md +224 -0
  123. data/doc/AI_PROVENANCE.md +139 -0
  124. data/doc/ARCHITECTURE.md +920 -0
  125. data/doc/BEHAVIOUR.md +409 -0
  126. data/doc/BUILD.md +138 -0
  127. data/doc/CI_CD_RECIPES.md +171 -0
  128. data/doc/CLAUDE_SESSIONS_MOVED.md +16 -0
  129. data/doc/COMMAND_ANALYSIS.md +229 -0
  130. data/doc/CONFIGURATION.md +281 -0
  131. data/doc/DESIGN_AUDIT.md +235 -0
  132. data/doc/DESIGN_PEER_REVIEW.md +771 -0
  133. data/doc/DESKTOP.md +447 -0
  134. data/doc/ENGINES.md +567 -0
  135. data/doc/ENGINE_DEVELOPMENT_GUIDE.md +417 -0
  136. data/doc/FEATURE_AUDIT.md +218 -0
  137. data/doc/IMPLEMENTATION_PLAN.md +669 -0
  138. data/doc/INCIDENT_REPORT_2026-02-02.md +251 -0
  139. data/doc/MIGRATION_GUIDE.md +88 -0
  140. data/doc/PACKAGING.md +232 -0
  141. data/doc/PROJECT_DASHBOARD.md +153 -0
  142. data/doc/PULP_DEPLOYMENT.md +164 -0
  143. data/doc/QUALITY_FIX_SUMMARY.md +110 -0
  144. data/doc/QUICK_START.md +162 -0
  145. data/doc/REEK_CONFIGURATION.md +166 -0
  146. data/doc/REFERENCE.md +253 -0
  147. data/doc/REFERENCES.md +324 -0
  148. data/doc/SECURITY_REVIEW_CHECKLIST.md +72 -0
  149. data/doc/SESSION_2026-02-28_GTK4_HARDENING.md +359 -0
  150. data/doc/SETUP.md +202 -0
  151. data/doc/TEST_PEER_REVIEW.md +152 -0
  152. data/doc/THREAT_MODEL.md +230 -0
  153. data/doc/USAGE.md +545 -0
  154. data/doc/USER_MANUAL.md +585 -0
  155. data/doc/ai_test_review_checklist.md +110 -0
  156. data/doc/changes/2026-02-18-packaging-fpm.md +155 -0
  157. data/doc/changes/2026-02-19-testing-infrastructure.md +221 -0
  158. data/doc/changes/2026-02-20-security-implementation.md +281 -0
  159. data/doc/changes/2026-02-20-styles-implementation.md +220 -0
  160. data/doc/changes/2026-02-21-architecture-completion.md +95 -0
  161. data/doc/changes/2026-02-21-architecture-ui-layer.md +253 -0
  162. data/doc/changes/2026-02-21-cc-config-implementation.md +108 -0
  163. data/doc/changes/2026-02-21-ci-pipeline-implementation.md +214 -0
  164. data/doc/changes/2026-02-21-compiler-multi-target-pipeline.md +241 -0
  165. data/doc/changes/2026-02-21-config-design-show-commands.md +61 -0
  166. data/doc/changes/2026-02-21-design-implementation-overview.md +455 -0
  167. data/doc/changes/2026-02-21-lifecycle-management.md +196 -0
  168. data/doc/changes/2026-02-21-path-resolver.md +128 -0
  169. data/doc/changes/2026-02-24-ci-tmpdir-mutant-fetch.md +45 -0
  170. data/doc/changes/2026-03-01-ci-bundler-strategy.md +120 -0
  171. data/doc/changes/2026-03-20-security-hardening-phase2.md +163 -0
  172. data/doc/context/SESSION-HANDOFF.md +69 -0
  173. data/doc/context/ai-engine-usage-trends-2026.md +80 -0
  174. data/doc/context/plan-pluggable-engines.md +590 -0
  175. data/doc/decisions/001-flog-deferred.md +32 -0
  176. data/doc/decisions/002-path-resolution-strategy.md +158 -0
  177. data/doc/decisions/003-ui-adapter-selection.md +193 -0
  178. data/doc/decisions/004-design-document-validation.md +179 -0
  179. data/doc/decisions/005-package-splitting-strategy.md +200 -0
  180. data/doc/decisions/006-multi-engine-architecture.md +147 -0
  181. data/doc/decisions/007-engine-agnostic-pivot.md +219 -0
  182. data/doc/decisions/008-ci-bundler-strategy.md +129 -0
  183. data/doc/decisions/009-core-only-v1-release.md +60 -0
  184. data/doc/decisions/010-engine-debian-packaging.md +66 -0
  185. data/doc/decisions/011-context-aware-cli.md +71 -0
  186. data/doc/dependency_decisions.yml +247 -0
  187. data/doc/issues/001-wrapper-missing-environment-variables.md +197 -0
  188. data/doc/issues/002-embedded-ruby-wrong-prefix.md +217 -0
  189. data/doc/issues/003-smoke-test-false-positive.md +127 -0
  190. data/doc/issues/004-market-research-design-updates.md +109 -0
  191. data/doc/issues/005-compile-scope-coexistence.md +161 -0
  192. data/doc/locales/.gitkeep +0 -0
  193. data/doc/man/rai.1.ronn +505 -0
  194. data/doc/operations/packaging.md +133 -0
  195. data/doc/operations/rosett-ai-release.md +65 -0
  196. data/doc/reference/error-catalog.md +107 -0
  197. data/doc/reference/rosett-ai-technical-reference.pdf +0 -0
  198. data/doc/reference/src/Pictures/cover.jpg +0 -0
  199. data/doc/reference/src/Pictures/head1.jpg +0 -0
  200. data/doc/reference/src/Pictures/head2.jpg +0 -0
  201. data/doc/reference/src/Pictures/head3.jpg +0 -0
  202. data/doc/reference/src/Pictures/head4.jpg +0 -0
  203. data/doc/reference/src/Pictures/head5.jpg +0 -0
  204. data/doc/reference/src/Pictures/head6.jpg +0 -0
  205. data/doc/reference/src/Pictures/head7.jpg +0 -0
  206. data/doc/reference/src/Pictures/head8.jpg +0 -0
  207. data/doc/reference/src/StyleInd.ist +4 -0
  208. data/doc/reference/src/bibliography.bib +79 -0
  209. data/doc/reference/src/main.tex +1288 -0
  210. data/doc/reference/src/structure.tex +303 -0
  211. data/doc/rosett-ai-bookmarks.html +301 -0
  212. data/kitchen.yml +46 -0
  213. data/lib/rosett_ai/adopter/executor_resolver.rb +77 -0
  214. data/lib/rosett_ai/adopter/local_analysis_collector.rb +154 -0
  215. data/lib/rosett_ai/adopter/rule_adopter.rb +254 -0
  216. data/lib/rosett_ai/ai_config/config_compiler.rb +111 -0
  217. data/lib/rosett_ai/ai_config/context_window.rb +55 -0
  218. data/lib/rosett_ai/ai_config/cost_controls.rb +44 -0
  219. data/lib/rosett_ai/ai_config/fallback_chain.rb +64 -0
  220. data/lib/rosett_ai/ai_config/model_router.rb +121 -0
  221. data/lib/rosett_ai/ai_config/validator.rb +45 -0
  222. data/lib/rosett_ai/authorship/attribution_compiler.rb +99 -0
  223. data/lib/rosett_ai/authorship/disclosure_policy.rb +81 -0
  224. data/lib/rosett_ai/authorship/review_validator.rb +39 -0
  225. data/lib/rosett_ai/authorship/trailer_generator.rb +88 -0
  226. data/lib/rosett_ai/backup/compressor.rb +180 -0
  227. data/lib/rosett_ai/backup/destination.rb +91 -0
  228. data/lib/rosett_ai/behaviour/manager.rb +156 -0
  229. data/lib/rosett_ai/compiler/backend.rb +86 -0
  230. data/lib/rosett_ai/compiler/backends/agents_md_backend.rb +80 -0
  231. data/lib/rosett_ai/compiler/backends/claude_backend.rb +88 -0
  232. data/lib/rosett_ai/compiler/backends/generic_backend.rb +15 -0
  233. data/lib/rosett_ai/compiler/behaviour_compiler.rb +40 -0
  234. data/lib/rosett_ai/compiler/capability_checker.rb +104 -0
  235. data/lib/rosett_ai/compiler/compilation_pipeline.rb +361 -0
  236. data/lib/rosett_ai/compiler/compiled_output.rb +39 -0
  237. data/lib/rosett_ai/compiler/locale_compiler.rb +250 -0
  238. data/lib/rosett_ai/compiler/target_profile.rb +112 -0
  239. data/lib/rosett_ai/completion/generator.rb +101 -0
  240. data/lib/rosett_ai/completion/shells/bash_generator.rb +126 -0
  241. data/lib/rosett_ai/completion/shells/fish_generator.rb +78 -0
  242. data/lib/rosett_ai/completion/shells/zsh_generator.rb +126 -0
  243. data/lib/rosett_ai/comply/checkers/cra_checker.rb +102 -0
  244. data/lib/rosett_ai/comply/checkers/license_checker.rb +85 -0
  245. data/lib/rosett_ai/comply/checkers/spdx_header_checker.rb +98 -0
  246. data/lib/rosett_ai/comply/reporter.rb +113 -0
  247. data/lib/rosett_ai/comply/runner.rb +50 -0
  248. data/lib/rosett_ai/composition/circular_dependency_detector.rb +56 -0
  249. data/lib/rosett_ai/composition/composer.rb +158 -0
  250. data/lib/rosett_ai/composition/composition_result.rb +64 -0
  251. data/lib/rosett_ai/composition/conflict_detector.rb +53 -0
  252. data/lib/rosett_ai/composition/lockfile.rb +103 -0
  253. data/lib/rosett_ai/composition/merge_strategy.rb +131 -0
  254. data/lib/rosett_ai/composition/priority_sorter.rb +29 -0
  255. data/lib/rosett_ai/composition/scope_resolver.rb +55 -0
  256. data/lib/rosett_ai/config/compile_result.rb +37 -0
  257. data/lib/rosett_ai/config/compiler.rb +13 -0
  258. data/lib/rosett_ai/config/domain_transformer.rb +13 -0
  259. data/lib/rosett_ai/config/key_map.rb +13 -0
  260. data/lib/rosett_ai/config/masking_secret_resolver.rb +40 -0
  261. data/lib/rosett_ai/config/scope_router.rb +13 -0
  262. data/lib/rosett_ai/config/secret_resolver.rb +125 -0
  263. data/lib/rosett_ai/configuration.rb +119 -0
  264. data/lib/rosett_ai/content/content_client.rb +60 -0
  265. data/lib/rosett_ai/content/pack_installer.rb +117 -0
  266. data/lib/rosett_ai/content/pack_manifest.rb +50 -0
  267. data/lib/rosett_ai/content/pack_registry.rb +68 -0
  268. data/lib/rosett_ai/content_packs/manager.rb +50 -0
  269. data/lib/rosett_ai/dbus/compositor_detector.rb +77 -0
  270. data/lib/rosett_ai/dbus/focus_adapters/base.rb +59 -0
  271. data/lib/rosett_ai/dbus/focus_adapters/gnome_adapter.rb +172 -0
  272. data/lib/rosett_ai/dbus/focus_adapters/hyprland_adapter.rb +77 -0
  273. data/lib/rosett_ai/dbus/focus_adapters/i3_adapter.rb +65 -0
  274. data/lib/rosett_ai/dbus/focus_adapters/kwin_adapter.rb +103 -0
  275. data/lib/rosett_ai/dbus/focus_adapters/x11_adapter.rb +105 -0
  276. data/lib/rosett_ai/dbus/focus_monitor_interface.rb +103 -0
  277. data/lib/rosett_ai/dbus/manager_interface.rb +213 -0
  278. data/lib/rosett_ai/dbus/plugin_manager_interface.rb +169 -0
  279. data/lib/rosett_ai/dbus/rate_limiter.rb +89 -0
  280. data/lib/rosett_ai/dbus/service.rb +121 -0
  281. data/lib/rosett_ai/dbus/status_notifier_interface.rb +79 -0
  282. data/lib/rosett_ai/deprecation.rb +79 -0
  283. data/lib/rosett_ai/desktop/dbus_client.rb +259 -0
  284. data/lib/rosett_ai/desktop/gtk4_app.rb +371 -0
  285. data/lib/rosett_ai/desktop/gtk4_preferences.rb +331 -0
  286. data/lib/rosett_ai/desktop/gui_logger.rb +236 -0
  287. data/lib/rosett_ai/doctor/check.rb +92 -0
  288. data/lib/rosett_ai/doctor/checks/cache_health_check.rb +50 -0
  289. data/lib/rosett_ai/doctor/checks/dbus_availability_check.rb +39 -0
  290. data/lib/rosett_ai/doctor/checks/engine_detection_check.rb +46 -0
  291. data/lib/rosett_ai/doctor/checks/file_permission_check.rb +44 -0
  292. data/lib/rosett_ai/doctor/checks/gem_dependency_check.rb +55 -0
  293. data/lib/rosett_ai/doctor/checks/ruby_version_check.rb +50 -0
  294. data/lib/rosett_ai/doctor/checks/stale_config_nncc_check.rb +57 -0
  295. data/lib/rosett_ai/doctor/checks/stale_home_nncc_check.rb +59 -0
  296. data/lib/rosett_ai/doctor.rb +81 -0
  297. data/lib/rosett_ai/documentation/reference_compiler.rb +122 -0
  298. data/lib/rosett_ai/documentation/translator.rb +62 -0
  299. data/lib/rosett_ai/engines/base_config_compiler.rb +203 -0
  300. data/lib/rosett_ai/engines/detector.rb +63 -0
  301. data/lib/rosett_ai/engines/registry.rb +50 -0
  302. data/lib/rosett_ai/error_handler.rb +139 -0
  303. data/lib/rosett_ai/exit_codes.rb +76 -0
  304. data/lib/rosett_ai/feature_flags.rb +102 -0
  305. data/lib/rosett_ai/formatting.rb +33 -0
  306. data/lib/rosett_ai/gem_consistency_checker.rb +199 -0
  307. data/lib/rosett_ai/git_hooks/chain_detector.rb +86 -0
  308. data/lib/rosett_ai/git_hooks/installer.rb +175 -0
  309. data/lib/rosett_ai/git_hooks/script_generator.rb +125 -0
  310. data/lib/rosett_ai/gitlab/validators/supplementary_gitlab_ci_yaml_validator.rb +79 -0
  311. data/lib/rosett_ai/i18n/locale_resolver.rb +46 -0
  312. data/lib/rosett_ai/i18n/utf8_checker.rb +32 -0
  313. data/lib/rosett_ai/init/config_file_writer.rb +24 -0
  314. data/lib/rosett_ai/init/directory_builder.rb +38 -0
  315. data/lib/rosett_ai/init/file_copier.rb +95 -0
  316. data/lib/rosett_ai/init/global_initializer.rb +28 -0
  317. data/lib/rosett_ai/init/local_initializer.rb +27 -0
  318. data/lib/rosett_ai/init/mcp_registrar.rb +109 -0
  319. data/lib/rosett_ai/init/project_initializer.rb +38 -0
  320. data/lib/rosett_ai/licensing/license_key.rb +139 -0
  321. data/lib/rosett_ai/licensing/license_store.rb +64 -0
  322. data/lib/rosett_ai/licensing/license_validator.rb +60 -0
  323. data/lib/rosett_ai/licensing/tier.rb +42 -0
  324. data/lib/rosett_ai/mcp/admin/auditor.rb +88 -0
  325. data/lib/rosett_ai/mcp/admin/health_checker.rb +81 -0
  326. data/lib/rosett_ai/mcp/admin/registry.rb +100 -0
  327. data/lib/rosett_ai/mcp/admin/schema_validator.rb +63 -0
  328. data/lib/rosett_ai/mcp/enforcement/.gitkeep +0 -0
  329. data/lib/rosett_ai/mcp/enforcement/hook_generator.rb +197 -0
  330. data/lib/rosett_ai/mcp/enforcement/validator.rb +215 -0
  331. data/lib/rosett_ai/mcp/governance.rb +160 -0
  332. data/lib/rosett_ai/mcp/http_security_config.rb +158 -0
  333. data/lib/rosett_ai/mcp/instructions.rb +266 -0
  334. data/lib/rosett_ai/mcp/key_hasher.rb +66 -0
  335. data/lib/rosett_ai/mcp/keyfile.rb +221 -0
  336. data/lib/rosett_ai/mcp/middleware/authentication.rb +146 -0
  337. data/lib/rosett_ai/mcp/middleware/content_type.rb +56 -0
  338. data/lib/rosett_ai/mcp/middleware/cors.rb +83 -0
  339. data/lib/rosett_ai/mcp/middleware/origin_validation.rb +73 -0
  340. data/lib/rosett_ai/mcp/middleware/rate_limit.rb +106 -0
  341. data/lib/rosett_ai/mcp/middleware/request_size.rb +51 -0
  342. data/lib/rosett_ai/mcp/plugins.rb +143 -0
  343. data/lib/rosett_ai/mcp/prompts/compilation_prompt.rb +40 -0
  344. data/lib/rosett_ai/mcp/prompts/compliance_prompt.rb +41 -0
  345. data/lib/rosett_ai/mcp/prompts/diagnostics_prompt.rb +41 -0
  346. data/lib/rosett_ai/mcp/prompts/validation_prompt.rb +41 -0
  347. data/lib/rosett_ai/mcp/resources/behaviour_resource.rb +127 -0
  348. data/lib/rosett_ai/mcp/resources/config_resource.rb +72 -0
  349. data/lib/rosett_ai/mcp/resources/design_resource.rb +58 -0
  350. data/lib/rosett_ai/mcp/resources/hooks_resource.rb +74 -0
  351. data/lib/rosett_ai/mcp/resources/provenance_resource.rb +51 -0
  352. data/lib/rosett_ai/mcp/resources/rules_resource.rb +60 -0
  353. data/lib/rosett_ai/mcp/resources/schema_resource.rb +72 -0
  354. data/lib/rosett_ai/mcp/response_helper.rb +46 -0
  355. data/lib/rosett_ai/mcp/security_logger.rb +60 -0
  356. data/lib/rosett_ai/mcp/server.rb +212 -0
  357. data/lib/rosett_ai/mcp/settings/server_installer.rb +112 -0
  358. data/lib/rosett_ai/mcp/settings/trust_manager.rb +142 -0
  359. data/lib/rosett_ai/mcp/tools/adopt_tool.rb +70 -0
  360. data/lib/rosett_ai/mcp/tools/backup_tool.rb +64 -0
  361. data/lib/rosett_ai/mcp/tools/behaviour_display_tool.rb +72 -0
  362. data/lib/rosett_ai/mcp/tools/behaviour_list_tool.rb +56 -0
  363. data/lib/rosett_ai/mcp/tools/behaviour_manage_tool.rb +114 -0
  364. data/lib/rosett_ai/mcp/tools/behaviour_show_tool.rb +62 -0
  365. data/lib/rosett_ai/mcp/tools/compile_status_tool.rb +122 -0
  366. data/lib/rosett_ai/mcp/tools/compile_tool.rb +191 -0
  367. data/lib/rosett_ai/mcp/tools/comply_tool.rb +79 -0
  368. data/lib/rosett_ai/mcp/tools/config_compile_tool.rb +71 -0
  369. data/lib/rosett_ai/mcp/tools/config_status_tool.rb +79 -0
  370. data/lib/rosett_ai/mcp/tools/content_tool.rb +78 -0
  371. data/lib/rosett_ai/mcp/tools/context_query_tool.rb +156 -0
  372. data/lib/rosett_ai/mcp/tools/design_list_tool.rb +57 -0
  373. data/lib/rosett_ai/mcp/tools/design_show_tool.rb +69 -0
  374. data/lib/rosett_ai/mcp/tools/doctor_tool.rb +62 -0
  375. data/lib/rosett_ai/mcp/tools/documentation_status_tool.rb +45 -0
  376. data/lib/rosett_ai/mcp/tools/engines_tool.rb +84 -0
  377. data/lib/rosett_ai/mcp/tools/hook_install_tool.rb +190 -0
  378. data/lib/rosett_ai/mcp/tools/hook_preview_tool.rb +173 -0
  379. data/lib/rosett_ai/mcp/tools/hooks_status_tool.rb +84 -0
  380. data/lib/rosett_ai/mcp/tools/init_tool.rb +87 -0
  381. data/lib/rosett_ai/mcp/tools/license_status_tool.rb +44 -0
  382. data/lib/rosett_ai/mcp/tools/project_tool.rb +117 -0
  383. data/lib/rosett_ai/mcp/tools/provenance_tool.rb +97 -0
  384. data/lib/rosett_ai/mcp/tools/provenance_write_tool.rb +40 -0
  385. data/lib/rosett_ai/mcp/tools/retrofit_tool.rb +81 -0
  386. data/lib/rosett_ai/mcp/tools/rule_search_tool.rb +163 -0
  387. data/lib/rosett_ai/mcp/tools/schema_get_tool.rb +94 -0
  388. data/lib/rosett_ai/mcp/tools/tooling_tool.rb +86 -0
  389. data/lib/rosett_ai/mcp/tools/validate_tool.rb +105 -0
  390. data/lib/rosett_ai/mcp/tools/workflow_execute_tool.rb +74 -0
  391. data/lib/rosett_ai/mcp/tools/workflow_tool.rb +78 -0
  392. data/lib/rosett_ai/migration/detector.rb +117 -0
  393. data/lib/rosett_ai/migration/nncc_config_migrator.rb +94 -0
  394. data/lib/rosett_ai/migration/nncc_project_migrator.rb +90 -0
  395. data/lib/rosett_ai/migration/xdg_migrator.rb +123 -0
  396. data/lib/rosett_ai/package_manager/apt.rb +108 -0
  397. data/lib/rosett_ai/package_manager/base.rb +68 -0
  398. data/lib/rosett_ai/package_manager/gem_backend.rb +90 -0
  399. data/lib/rosett_ai/packaging/variant_config.rb +92 -0
  400. data/lib/rosett_ai/path_resolver.rb +115 -0
  401. data/lib/rosett_ai/plugins/contract.rb +43 -0
  402. data/lib/rosett_ai/plugins/engine_contract.rb +60 -0
  403. data/lib/rosett_ai/plugins/gui_contract.rb +74 -0
  404. data/lib/rosett_ai/plugins/mcp_contract.rb +48 -0
  405. data/lib/rosett_ai/plugins/registry.rb +150 -0
  406. data/lib/rosett_ai/policy/auditor.rb +41 -0
  407. data/lib/rosett_ai/policy/deny_list.rb +71 -0
  408. data/lib/rosett_ai/policy/opt_out_scanner.rb +37 -0
  409. data/lib/rosett_ai/policy/policy_compiler.rb +84 -0
  410. data/lib/rosett_ai/policy/protected_files.rb +47 -0
  411. data/lib/rosett_ai/policy/tier_hierarchy.rb +48 -0
  412. data/lib/rosett_ai/policy/validator.rb +35 -0
  413. data/lib/rosett_ai/profiler.rb +79 -0
  414. data/lib/rosett_ai/project/drift_detector.rb +126 -0
  415. data/lib/rosett_ai/project/manager.rb +115 -0
  416. data/lib/rosett_ai/project/sync_manager.rb +138 -0
  417. data/lib/rosett_ai/project/template_applier.rb +105 -0
  418. data/lib/rosett_ai/project_context.rb +82 -0
  419. data/lib/rosett_ai/provenance/entry.rb +63 -0
  420. data/lib/rosett_ai/provenance/file_source.rb +32 -0
  421. data/lib/rosett_ai/provenance/source.rb +62 -0
  422. data/lib/rosett_ai/provenance/store.rb +153 -0
  423. data/lib/rosett_ai/provenance/tracker.rb +62 -0
  424. data/lib/rosett_ai/provenance/trailer_generator.rb +43 -0
  425. data/lib/rosett_ai/provenance/validator.rb +45 -0
  426. data/lib/rosett_ai/quorum/collector.rb +59 -0
  427. data/lib/rosett_ai/quorum/comparator.rb +81 -0
  428. data/lib/rosett_ai/quorum/dispatcher.rb +57 -0
  429. data/lib/rosett_ai/quorum/strategies/adopt.rb +56 -0
  430. data/lib/rosett_ai/rai_config.rb +107 -0
  431. data/lib/rosett_ai/retrofit/base_parser.rb +66 -0
  432. data/lib/rosett_ai/retrofit/engine.rb +171 -0
  433. data/lib/rosett_ai/retrofit/parsers/agents_md_parser.rb +50 -0
  434. data/lib/rosett_ai/retrofit/parsers/claude_parser.rb +69 -0
  435. data/lib/rosett_ai/retrofit/parsers/cursor_parser.rb +82 -0
  436. data/lib/rosett_ai/retrofit/round_trip_validator.rb +65 -0
  437. data/lib/rosett_ai/retrofit/scanner.rb +47 -0
  438. data/lib/rosett_ai/retrofit/secret_detector.rb +87 -0
  439. data/lib/rosett_ai/secrets_resolver.rb +71 -0
  440. data/lib/rosett_ai/smart_feedback/suggester.rb +83 -0
  441. data/lib/rosett_ai/smart_feedback/thor_middleware.rb +84 -0
  442. data/lib/rosett_ai/structured_logger.rb +110 -0
  443. data/lib/rosett_ai/telemetry/json_lines_writer.rb +50 -0
  444. data/lib/rosett_ai/telemetry/log_rotator.rb +67 -0
  445. data/lib/rosett_ai/telemetry/provider.rb +26 -0
  446. data/lib/rosett_ai/telemetry/reporter.rb +144 -0
  447. data/lib/rosett_ai/telemetry.rb +47 -0
  448. data/lib/rosett_ai/text_sanitizer.rb +62 -0
  449. data/lib/rosett_ai/thor/cli.rb +269 -0
  450. data/lib/rosett_ai/thor/tasks/adopt.rb +250 -0
  451. data/lib/rosett_ai/thor/tasks/backup.rb +420 -0
  452. data/lib/rosett_ai/thor/tasks/behaviour.rb +474 -0
  453. data/lib/rosett_ai/thor/tasks/build.rb +1162 -0
  454. data/lib/rosett_ai/thor/tasks/compile.rb +415 -0
  455. data/lib/rosett_ai/thor/tasks/completion.rb +123 -0
  456. data/lib/rosett_ai/thor/tasks/comply.rb +82 -0
  457. data/lib/rosett_ai/thor/tasks/config.rb +265 -0
  458. data/lib/rosett_ai/thor/tasks/content.rb +193 -0
  459. data/lib/rosett_ai/thor/tasks/dbus.rb +321 -0
  460. data/lib/rosett_ai/thor/tasks/design.rb +258 -0
  461. data/lib/rosett_ai/thor/tasks/desktop.rb +129 -0
  462. data/lib/rosett_ai/thor/tasks/doctor.rb +127 -0
  463. data/lib/rosett_ai/thor/tasks/documentation.rb +321 -0
  464. data/lib/rosett_ai/thor/tasks/engines.rb +167 -0
  465. data/lib/rosett_ai/thor/tasks/hooks.rb +219 -0
  466. data/lib/rosett_ai/thor/tasks/init.rb +259 -0
  467. data/lib/rosett_ai/thor/tasks/license.rb +120 -0
  468. data/lib/rosett_ai/thor/tasks/mcp.rb +535 -0
  469. data/lib/rosett_ai/thor/tasks/migrate.rb +121 -0
  470. data/lib/rosett_ai/thor/tasks/plugins.rb +157 -0
  471. data/lib/rosett_ai/thor/tasks/project.rb +260 -0
  472. data/lib/rosett_ai/thor/tasks/provenance.rb +195 -0
  473. data/lib/rosett_ai/thor/tasks/release.rb +314 -0
  474. data/lib/rosett_ai/thor/tasks/retrofit.rb +90 -0
  475. data/lib/rosett_ai/thor/tasks/tooling.rb +308 -0
  476. data/lib/rosett_ai/thor/tasks/validate.rb +108 -0
  477. data/lib/rosett_ai/thor/tasks/workflow.rb +196 -0
  478. data/lib/rosett_ai/tooling/ci_yaml_validator.rb +37 -0
  479. data/lib/rosett_ai/tooling/version_checker.rb +35 -0
  480. data/lib/rosett_ai/ui/accessible_tui.rb +61 -0
  481. data/lib/rosett_ai/ui/base.rb +46 -0
  482. data/lib/rosett_ai/ui/gtk4.rb +98 -0
  483. data/lib/rosett_ai/ui/kde.rb +40 -0
  484. data/lib/rosett_ai/ui/qt6.rb +40 -0
  485. data/lib/rosett_ai/ui/registry.rb +60 -0
  486. data/lib/rosett_ai/ui/tty_helper.rb +74 -0
  487. data/lib/rosett_ai/ui/tui.rb +59 -0
  488. data/lib/rosett_ai/validators/behaviour_validator.rb +20 -0
  489. data/lib/rosett_ai/validators/design_validator.rb +17 -0
  490. data/lib/rosett_ai/validators/schema_validator.rb +84 -0
  491. data/lib/rosett_ai/validators/tooling_validator.rb +17 -0
  492. data/lib/rosett_ai/version.rb +8 -0
  493. data/lib/rosett_ai/version_consistency_checker.rb +129 -0
  494. data/lib/rosett_ai/workflow/audit_log.rb +86 -0
  495. data/lib/rosett_ai/workflow/engine.rb +142 -0
  496. data/lib/rosett_ai/workflow/manager.rb +82 -0
  497. data/lib/rosett_ai/workflow/schema_validator.rb +71 -0
  498. data/lib/rosett_ai/workflow/step_runner.rb +61 -0
  499. data/lib/rosett_ai/workflow/steps/prompt_step.rb +62 -0
  500. data/lib/rosett_ai/workflow/steps/rai_step.rb +74 -0
  501. data/lib/rosett_ai/workflow/steps/shell_step.rb +53 -0
  502. data/lib/rosett_ai/yaml_loader.rb +78 -0
  503. data/lib/rosett_ai.rb +221 -0
  504. data/lib/rubocop/cop/rosett_ai/shell_interpolation.rb +54 -0
  505. data/lib/rubocop/cop/rosett_ai/unsafe_const_get.rb +60 -0
  506. data/lib/rubocop/cop/rosett_ai/unsafe_send.rb +50 -0
  507. data/lib/rubocop/cop/rosett_ai/unsafe_yaml_load.rb +40 -0
  508. data/lib/rubocop/rosett_ai.rb +9 -0
  509. data/lib/scripts/generated/docker_hub_tags.rb +126 -0
  510. data/locales/.gitkeep +0 -0
  511. data/locales/ar.yml +579 -0
  512. data/locales/en.yml +571 -0
  513. data/locales/fr.yml +567 -0
  514. data/packaging/build-engine-deb.sh +81 -0
  515. data/packaging/scripts/postinst +17 -0
  516. data/packaging/scripts/postrm +19 -0
  517. data/packaging/scripts/prerm +10 -0
  518. data/packaging/wrapper.sh.template +38 -0
  519. data/rosett-ai.gemspec +63 -0
  520. data/rules/.gitkeep +0 -0
  521. data/scripts/publish/pulp_upload.sh +123 -0
  522. data/settings.json +29 -0
  523. data/share/applications/be.neatnerds.rosettai.desktop +29 -0
  524. data/share/dbus-1/interfaces/be.neatnerds.rosettai.xml +103 -0
  525. data/share/dbus-1/services/be.neatnerds.rosettai.service +3 -0
  526. data/share/templates/behaviour/criticalthinking.yml +69 -0
  527. metadata +810 -0
@@ -0,0 +1,200 @@
1
+ # ADR-005: Package Splitting Strategy
2
+
3
+ ## Status
4
+
5
+ Accepted (2026-02-21) — implementation deferred to P3/P4
6
+
7
+ ## Context
8
+
9
+ The `architecture.yml` design document requires that GUI frontends are
10
+ delivered as separate Debian packages (`rosett-ai-gtk4`, `rosett-ai-qt6`, `rosett-ai-kde`)
11
+ that depend on the core `rosett-ai` package. The core must be fully functional
12
+ without any GUI package installed.
13
+
14
+ The `RosettAi::Ui::Registry` pattern is already in place. Adapters register
15
+ themselves at require time, and `Registry.resolve(name)` instantiates the
16
+ requested adapter. The TUI adapter is the default and the only adapter
17
+ currently implemented.
18
+
19
+ The build infrastructure exists: fpm-based `.deb` packaging via
20
+ `bin/raictl build package`.
21
+
22
+ The question is how to organise the source code for multiple packages.
23
+
24
+ ## Options
25
+
26
+ ### Option A: Monorepo with multiple gemspecs
27
+
28
+ Single Git repository with a directory per package:
29
+
30
+ ```text
31
+ rosett-ai/
32
+ ├── rosett-ai.gemspec # Core + TUI
33
+ ├── packages/
34
+ │ ├── rosett-ai-gtk4/
35
+ │ │ ├── rosett-ai-gtk4.gemspec
36
+ │ │ └── lib/rosett_ai/ui/gtk4.rb
37
+ │ ├── rosett-ai-qt6/
38
+ │ │ ├── rosett-ai-qt6.gemspec
39
+ │ │ └── lib/rosett_ai/ui/qt6.rb
40
+ ```
41
+
42
+ Pros:
43
+
44
+ - Atomic cross-package changes (interface + adapter in one commit)
45
+ - Single CI pipeline validates all packages together
46
+ - Shared test infrastructure
47
+
48
+ Cons:
49
+
50
+ - Repository grows with each GUI toolkit's dependencies
51
+ - CI must install GTK4, Qt6, and KDE libraries to test all packages
52
+ - fpm build configuration becomes complex
53
+ - Contributors must install all toolkit dev packages
54
+
55
+ ### Option B: Separate repositories
56
+
57
+ Core stays in this repository. Each GUI package gets its own repository
58
+ (`rosett-ai-gtk4`, `rosett-ai-qt6`).
59
+
60
+ Pros:
61
+
62
+ - Clean separation of concerns
63
+ - Independent CI pipelines with toolkit-specific dependencies
64
+ - Independent release cycles
65
+
66
+ Cons:
67
+
68
+ - Cross-repo coordination when Base interface changes
69
+ - Version drift risk between core and GUI packages
70
+ - Harder to run shared examples across repos
71
+ - Changes to shared_examples require multi-repo updates
72
+
73
+ ### Option C: Plugin gems within core repo
74
+
75
+ GUI adapter files live in the core repository under `lib/rosett_ai/ui/` but are
76
+ excluded from the core `rosett-ai.gemspec`. Each plugin has its own gemspec at the
77
+ repo root. Both core and plugins are built from the same repository but as
78
+ separate gems and separate `.deb` packages.
79
+
80
+ ```text
81
+ rosett-ai/
82
+ ├── rosett-ai.gemspec # Core: lib/rosett_ai/ui/{base,registry,tui}.rb
83
+ ├── rosett-ai-gtk4.gemspec # Plugin: lib/rosett_ai/ui/gtk4.rb
84
+ ├── rosett-ai-qt6.gemspec # Plugin: lib/rosett_ai/ui/qt6.rb
85
+ ├── lib/rosett_ai/ui/
86
+ │ ├── base.rb # Shipped in rosett-ai
87
+ │ ├── registry.rb # Shipped in rosett-ai
88
+ │ ├── tui.rb # Shipped in rosett-ai
89
+ │ ├── gtk4.rb # Shipped in rosett-ai-gtk4
90
+ │ └── qt6.rb # Shipped in rosett-ai-qt6
91
+ ├── spec/rosett_ai/ui/
92
+ │ ├── base_spec.rb
93
+ │ ├── tui_spec.rb
94
+ │ ├── gtk4_spec.rb # Runs shared_examples
95
+ │ └── qt6_spec.rb # Runs shared_examples
96
+ ```
97
+
98
+ Auto-registration at the bottom of each adapter file:
99
+
100
+ ```ruby
101
+ # lib/rosett_ai/ui/gtk4.rb
102
+ RosettAi::Ui::Registry.register(:gtk4, Gtk4)
103
+ ```
104
+
105
+ Debian packages:
106
+
107
+ - `rosett-ai` ships `lib/rosett_ai/ui/{base,registry,tui}.rb` + all core
108
+ - `rosett-ai-gtk4` ships `lib/rosett_ai/ui/gtk4.rb`, depends on `raictl (>= X.Y.Z)`
109
+ and `libgtk-4-dev`
110
+ - `rosett-ai-qt6` ships `lib/rosett_ai/ui/qt6.rb`, depends on `raictl (>= X.Y.Z)`
111
+ and `qt6-base-dev`
112
+
113
+ Pros:
114
+
115
+ - Shared examples validate all adapters against the same interface contract
116
+ - One CI pipeline — test matrix per toolkit (optional stages)
117
+ - Interface changes and adapter updates in the same commit
118
+ - `Registry.register` call in each adapter file provides auto-discovery
119
+ - fpm can build multiple `.deb` packages from the same source tree
120
+
121
+ Cons:
122
+
123
+ - Gemspec file exclusion lists must be maintained carefully
124
+ - CI needs conditional toolkit installation (only for GUI test stages)
125
+ - Contributors see all adapter code even if they only work on one
126
+
127
+ ## Decision
128
+
129
+ **Option C: Plugin gems within core repository** — because:
130
+
131
+ - The shared_examples pattern (`'a UI implementation'`) is already in place
132
+ and validates the 7-method interface contract. Running these examples
133
+ against all adapters in one CI pipeline catches interface drift immediately.
134
+ - `Registry.register(:gtk4, Gtk4)` at the bottom of `gtk4.rb` provides
135
+ automatic discovery — no configuration files, no plugin manifests.
136
+ - The fpm-based build can produce multiple `.deb` packages from the same
137
+ source tree by varying the file inclusion list.
138
+ - When `Base` adds a new abstract method (as happened with `announce`,
139
+ `accessible?`, `text_direction`), all adapter specs fail in the same CI
140
+ run, forcing immediate fixes.
141
+
142
+ ## Consequences
143
+
144
+ Implementation is deferred to P3 (ui_framework) and P4 (packaging), but the
145
+ architecture is documented now:
146
+
147
+ - Future: `lib/rosett_ai/ui/gtk4.rb` + `rosett-ai-gtk4.gemspec` added to this repo
148
+ - Debian `Depends:` on `raictl (>= current_version)` for all GUI packages
149
+ - CI test matrix: core tests always run; GTK4/Qt6 tests run conditionally
150
+ based on toolkit availability
151
+ - Shared examples validate all registered adapters in a single CI run
152
+ - No code changes needed now — the Registry pattern already supports this
153
+
154
+ ### P4 detail: variant packaging
155
+
156
+ `bin/raictl build package` will be extended with a `--variant` flag:
157
+
158
+ ```bash
159
+ bin/raictl build package --variant core # Core + TUI only (default)
160
+ bin/raictl build package --variant gtk4 # rosett-ai-gtk4 .deb only
161
+ bin/raictl build package --variant qt6 # Rosett-AI-qt6 .deb only
162
+ bin/raictl build package --variant all # Build all packages in one invocation
163
+ ```
164
+
165
+ `--variant all` iterates over all known variants and produces one `.deb`
166
+ per variant. This is the expected invocation for release automation.
167
+
168
+ ### P3/P4 detail: GUI adapter testing
169
+
170
+ Every UI adapter — TUI and GUI — must have maximum test coverage. The TUI
171
+ adapter is testable with standard RSpec (no display server required). GUI
172
+ adapters require a different strategy because they render to a display.
173
+
174
+ GUI testing approaches to evaluate during P3 implementation:
175
+
176
+ | Approach | How it works | Toolkit support |
177
+ |----------|-------------|-----------------|
178
+ | Headless display (Xvfb) | Virtual X11 framebuffer; no physical display needed | GTK4, Qt6, KDE |
179
+ | ATK/AT-SPI introspection | Query widget tree via accessibility API; assert structure and state | GTK4 (native), Qt6 (via bridge) |
180
+ | dogtail / ldtp | Python libraries that drive GUI apps via AT-SPI; can click, type, assert | GTK4, Qt6 |
181
+ | GLib test harness | GTK's own `Gtk.test_*` functions for widget testing | GTK4 only |
182
+ | Qt Test / QTest | Qt's built-in test framework with `QTest::mouseClick`, `QTest::keyPress` | Qt6 only |
183
+ | Screenshot comparison | Render to headless display, capture screenshot, compare against baseline | Any toolkit |
184
+
185
+ The recommended layered approach:
186
+
187
+ 1. **Unit tests** (RSpec + shared_examples): validate that each adapter
188
+ implements the Base interface contract. No display server needed — mock
189
+ the toolkit bindings. This is the primary coverage layer.
190
+ 2. **Integration tests** (Xvfb + AT-SPI): run the adapter in a headless
191
+ display, query the widget tree via accessibility introspection. This
192
+ validates that widgets are created and accessible. Runs in CI with
193
+ `xvfb-run`.
194
+ 3. **Smoke tests** (optional, P4): screenshot comparison for visual
195
+ regression. Fragile and toolkit-version-sensitive, so only for release
196
+ validation, not CI gatekeeping.
197
+
198
+ The accessibility introspection approach (layer 2) has a natural synergy
199
+ with ADR-003's EN 301 549 compliance requirement — if the widget tree is
200
+ queryable via AT-SPI, the application is accessible by construction.
@@ -0,0 +1,147 @@
1
+ # ADR-006: Multi-Engine Architecture
2
+
3
+ ## Status
4
+
5
+ Proposed (2026-02-21)
6
+
7
+ ## Context
8
+
9
+ rosett-ai's stated goal is to be a configuration management tool for AI-assisted
10
+ development workflows. While the initial implementation targets Claude Code
11
+ exclusively, the architecture should not preclude support for other AI coding
12
+ engines. The intent is "one program to rule them all" — author configuration
13
+ once, compile to multiple engines, potentially invoke several simultaneously.
14
+
15
+ Each engine has its own directory conventions, configuration format, and
16
+ operational model:
17
+
18
+ | Engine | Global config | Local config | Format |
19
+ |--------|--------------|-------------|--------|
20
+ | Claude Code | `~/.claude/` | `.claude/` | JSON + Markdown rules |
21
+ | Cursor | `~/.cursor/` | `.cursor/` | JSON |
22
+ | Windsurf (Codeium) | `~/.codeium/windsurf/` | `.windsurf/` | JSON |
23
+ | Aider | `~/.aider.conf.yml` | `.aider.conf.yml` | YAML |
24
+ | Continue.dev | `~/.continue/` | `.continue/` | JSON |
25
+
26
+ ADR-002 (accepted) establishes `RosettAi::PathResolver` as the centralised path
27
+ resolution module. This ADR extends that concept to accommodate multiple
28
+ engines, and defines the compiler adapter pattern for generating
29
+ engine-native configuration files.
30
+
31
+ ### Relationship to existing design documents
32
+
33
+ - `architecture.yml` defines the multi-target AI compilation goal
34
+ - `compiler.yml` covers the compilation pipeline (currently Claude-only)
35
+ - `claude_code_configuration.yml` covers Claude Code settings specifically
36
+ - ADR-002 establishes PathResolver (currently Claude-only)
37
+
38
+ ### Design constraint: no ERB for machine-parsed output
39
+
40
+ Templating engines like ERB were considered for generating native config
41
+ files (JSON, YAML). This was rejected on security and correctness grounds:
42
+
43
+ - ERB is `Kernel#eval` under the hood, widening the attack surface beyond
44
+ what the security design document permits
45
+ - ERB-in-JSON is fragile: indentation, trailing commas, and quote escaping
46
+ are common sources of invalid output
47
+ - Programmatic hash construction (`Hash` → `JSON.generate`) guarantees
48
+ valid output by construction and keeps data separated from logic
49
+
50
+ The existing pattern — YAML data → Ruby hash transforms → native format —
51
+ is safer, testable, and sufficient for all known engine config formats.
52
+
53
+ ## Options
54
+
55
+ ### Option A: Engine-aware PathResolver + compiler adapters
56
+
57
+ Extend `PathResolver` with an engine registry. Each engine declares its
58
+ path conventions. A parallel compiler adapter pattern transforms rosett-ai's
59
+ canonical YAML into each engine's native format.
60
+
61
+ ```ruby
62
+ # Path resolution
63
+ PathResolver.for(:claude).global_dir # => ~/.claude
64
+ PathResolver.for(:cursor).global_dir # => ~/.cursor
65
+ PathResolver.for(:aider).config_file # => ~/.aider.conf.yml
66
+
67
+ # Compilation
68
+ EngineCompiler.for(:claude).compile(source) # => JSON + Markdown
69
+ EngineCompiler.for(:cursor).compile(source) # => JSON
70
+ EngineCompiler.for(:aider).compile(source) # => YAML
71
+ ```
72
+
73
+ Engine definitions live in `conf/engines/<name>.yml` and declare paths,
74
+ format, and compiler class. New engines are added by writing a YAML
75
+ definition and a compiler adapter — no changes to core code.
76
+
77
+ Pros:
78
+
79
+ - Clean separation: paths in PathResolver, transforms in compiler adapters
80
+ - New engines require zero changes to existing code
81
+ - Shared test infrastructure via shared_examples (same pattern as UI adapters)
82
+ - Each compiler adapter is independently testable
83
+ - Data/logic separation maintained (no eval surface)
84
+
85
+ Cons:
86
+
87
+ - Significant design work before implementation
88
+ - Engine config formats may diverge enough that a common YAML source is
89
+ impractical for some engines
90
+ - Risk of premature abstraction if only Claude Code is used for a long time
91
+
92
+ ### Option B: Separate tool per engine
93
+
94
+ Create independent executables: `rosett-ai-claude`, `rosett-ai-cursor`, etc. Each
95
+ is self-contained with its own paths and compiler.
96
+
97
+ Pros:
98
+
99
+ - Maximum simplicity per engine
100
+ - No abstraction overhead
101
+
102
+ Cons:
103
+
104
+ - Duplicated logic across tools
105
+ - No unified workflow for multi-engine users
106
+ - Contradicts the "one program to rule them all" goal
107
+
108
+ ### Option C: Plugin-only extensibility
109
+
110
+ Keep rosett-ai Claude-only in core. Third-party plugins add engine support.
111
+
112
+ Pros:
113
+
114
+ - Core stays simple
115
+ - Community can contribute engines
116
+
117
+ Cons:
118
+
119
+ - No guarantee of interface consistency
120
+ - Plugin API must be designed and maintained
121
+ - Quality control is harder across third-party code
122
+
123
+ ## Decision
124
+
125
+ Deferred — this ADR captures the architectural direction established during
126
+ ADR-002 review. The recommended approach is **Option A**, but implementation
127
+ details require further analysis during the compiler design phase (P2).
128
+
129
+ Key principles agreed:
130
+
131
+ 1. PathResolver must be designed with engine extensibility in mind
132
+ 2. Compiler adapters (not templates) transform YAML to native formats
133
+ 3. No ERB or eval-based templating for machine-parsed output
134
+ 4. Engine definitions are declarative (YAML), not code-driven
135
+ 5. The existing Claude Code implementation is the first adapter, not a
136
+ special case
137
+
138
+ ## Consequences
139
+
140
+ - PathResolver (ADR-002) should use a design that can later accept an
141
+ engine parameter without breaking the current single-engine API
142
+ - The compiler design document should acknowledge multi-engine as a
143
+ future requirement
144
+ - No implementation work is needed now — Claude Code remains the only
145
+ target until this ADR is accepted and scheduled
146
+ - When implemented, `conf/engines/claude.yml` would replace the
147
+ hardcoded Claude Code assumptions in the current compiler
@@ -0,0 +1,219 @@
1
+ # ADR-007: Engine-Agnostic Architecture Pivot
2
+
3
+ ## Status
4
+
5
+ Accepted (2026-02-26) — supersedes ADR-006 (Proposed)
6
+
7
+ ## Context
8
+
9
+ raictl was designed as a configuration management tool for AI-assisted
10
+ development workflows. Despite the stated goal of AI-agnosticism, the
11
+ implementation is Claude Code-centric: the project is named "NeatNerds
12
+ Claude Companion", rosett-ai lives inside `~/.claude/`, the config compiler
13
+ targets Claude Code's `settings.json` format, and the adopt system
14
+ hard-depends on the Anthropic API.
15
+
16
+ A comprehensive audit (2026-02-26) revealed:
17
+
18
+ - **2 hard couplings**: Config compilation (100% Claude Code) and Adopt
19
+ API analysis (Anthropic-only)
20
+ - **3 soft couplings**: Default output paths, CLI description strings,
21
+ documentation references
22
+ - **Existing abstraction**: The compiler already has a multi-target
23
+ backend pattern (ClaudeBackend, GenericBackend) via strategy pattern
24
+
25
+ A structured Q&A session produced 9 architectural decisions that resolve
26
+ ADR-006's deferred status and define the concrete path to AI-agnosticism.
27
+
28
+ ### Relationship to existing ADRs and design documents
29
+
30
+ - **ADR-006** (Proposed): Identified multi-engine as a future need,
31
+ recommended Option A (engine-aware PathResolver + compiler adapters),
32
+ but deferred implementation. This ADR accepts and extends that
33
+ direction with specific decisions.
34
+ - **ADR-002** (Accepted): PathResolver with `engine:` parameter — already
35
+ designed for multi-engine, just not activated.
36
+ - **ADR-005** (Accepted): Package splitting strategy — applies to engine
37
+ packages (`rosett-ai-engine-*`) in addition to UI packages.
38
+ - `architecture.yml`: Must be updated to reflect engine-agnostic core.
39
+ - `compiler.yml`: Multi-target pipeline already designed; `--target`
40
+ renamed to `--engine`.
41
+ - `claude_code_configuration.yml`: Becomes Claude engine-specific config.
42
+ - `aaif_alignment.yml`: AGENTS.md becomes a first-class engine.
43
+
44
+ ## Decisions
45
+
46
+ ### Q1: Identity & Naming
47
+
48
+ **Decision**: Rename from "NeatNerds Claude Companion" to **"NeatNerds
49
+ Code Companion"**. The acronym `rosett-ai` is preserved. Binary name, package
50
+ names (`rosett-ai`, `rosett-ai-gtk4`, `rosett-ai-kde`), and repository name are unchanged.
51
+
52
+ Rationale: Path of least resistance. The acronym survives, all CLI
53
+ commands stay `rosett-ai`, `.deb` package names don't change, git history is
54
+ continuous.
55
+
56
+ Scope: gemspec summary/description, CLAUDE.md headers, i18n strings,
57
+ doc headers, CLI descriptions. SPDX copyright lines are unaffected
58
+ (they reference the author, not the product).
59
+
60
+ Note: GitLab project description must be updated manually by the
61
+ project owner.
62
+
63
+ ### Q2: Generic vs Engine-Specific Layers
64
+
65
+ **Decision**: Strict separation. The generic layer captures **only**
66
+ human intent (behaviour rules, design constraints, coding standards).
67
+ Engine-specific configuration lives entirely inside each engine's own
68
+ config namespace (`conf/engines/<name>/`). No `extensions:` key in the
69
+ generic schema.
70
+
71
+ Each engine declares a **capability manifest** listing which generic
72
+ features it supports. At compile time, rosett-ai warns about gaps:
73
+
74
+ ```text
75
+ WARN behaviour/security_internal.yml: sensitive filtering not supported
76
+ by cursor engine — file included without redaction (review manually)
77
+ ```
78
+
79
+ Warnings are non-fatal by default. A `--strict` flag makes them fatal
80
+ for CI gating.
81
+
82
+ ### Q3: Engine Registry Architecture
83
+
84
+ **Decision**: Option C — **engine as namespace directory**. Each AI tool
85
+ is a self-contained directory under `lib/rosett_ai/engines/<name>/` containing
86
+ independent, optional components:
87
+
88
+ ```text
89
+ lib/rosett_ai/engines/claude/
90
+ ├── backend.rb # Compiler backend
91
+ ├── config_adapter.rb # Settings compilation
92
+ ├── path_resolver.rb # Output paths
93
+ ├── scaffolder.rb # Init structure
94
+ ├── detector.rb # Autodetection
95
+ ├── executor.rb # API/CLI invocation (for quorum)
96
+ ├── validator.rb # Output validation
97
+ └── manifest.yml # Capabilities + required config + detection
98
+ ```
99
+
100
+ Components are optional. A trivial engine (Cursor) may only have
101
+ `backend.rb`, `detector.rb`, and `manifest.yml`. The engine registry
102
+ discovers entire directories. No forced common interface — each
103
+ component implements what's relevant and skips what isn't.
104
+
105
+ ### Q4: Config Compilation
106
+
107
+ **Decision**: Config compilation moves inside each engine. The current
108
+ `RosettAi::Config` namespace (KeyMap, ScopeRouter, DomainTransformer,
109
+ Compiler) becomes `RosettAi::Engines::Claude::ConfigAdapter` internals.
110
+
111
+ The `--target` flag is renamed to `--engine` universally. Default engine
112
+ is configurable, suggested by autodetection at `bin/raictl init` time.
113
+
114
+ Additional capabilities added to engine architecture:
115
+
116
+ - **Autodetection**: Each engine can detect if its AI tool is installed
117
+ (binary in PATH, config directory exists, env vars set). Detection is
118
+ data-driven from the manifest, with optional Ruby override for custom
119
+ logic. CLI: `bin/raictl engines list|detect|status`.
120
+ - **Quorum**: Separate module (`lib/rosett_ai/quorum/`) for dispatching the
121
+ same analysis to multiple engines and comparing results. Initial scope:
122
+ adopt use case only (structured findings comparison). Not an
123
+ orchestrator — rosett-ai stays configuration-focused.
124
+
125
+ ### Q5: Output Path Ownership
126
+
127
+ **Decision**: XDG-compliant paths. rosett-ai owns `~/.config/rosett-ai/` for its
128
+ own configuration. Compiled outputs deploy TO each engine's native
129
+ directory.
130
+
131
+ ```text
132
+ ~/.config/rosett-ai/ # Rosett-AI's own config (XDG_CONFIG_HOME)
133
+ ├── config.yml # default engine, quorum settings
134
+ ├── conf/behaviour/*.yml # source YAML (human intent)
135
+ ├── conf/design/*.yml # design documents
136
+ ├── conf/schemas/*.json # validation schemas
137
+ └── conf/engines/ # per-engine config
138
+ ├── claude/
139
+ ├── cursor/
140
+ └── goose/
141
+
142
+ # Compiled outputs deploy to each engine's native location:
143
+ ~/.claude/rules/ # Claude
144
+ ./.cursorrules # Cursor
145
+ ./AGENTS.md # AGENTS.md
146
+ ./.github/copilot-instructions.md # Copilot
147
+ ```
148
+
149
+ Consistent with ADR-002 (PathResolver) and existing XDG research.
150
+
151
+ ### Q6: Adopt System
152
+
153
+ **Decision**: Adopt defaults to local-only structural checks. API
154
+ analysis is opt-in via `--api` flag. The `--api` flag is quorum-capable.
155
+
156
+ ```bash
157
+ bin/raictl adopt # Local only (default)
158
+ bin/raictl adopt --api # Via default engine
159
+ bin/raictl adopt --api --engine claude # Via specific engine
160
+ bin/raictl adopt --api --quorum # All invocable engines
161
+ bin/raictl adopt --api --quorum --engines claude,ollama # Specific set
162
+ ```
163
+
164
+ The `anthropic` gem moves from rosett-ai core to the Claude engine's
165
+ dependencies. Core rosett-ai has zero LLM API dependencies.
166
+
167
+ ### Q7: Engine Scope & Phasing
168
+
169
+ **Decision**: Phased rollout, prioritising local testability:
170
+
171
+ | Phase | Engines | Rationale |
172
+ |-------|---------|-----------|
173
+ | 0 | Claude (restructure), Generic (restructure) | Prove architecture |
174
+ | 1 | AGENTS.md | First multi-engine story |
175
+ | 2 | Ollama, GPT-NeoX | Local quorum without paid APIs |
176
+ | 3 | Goose, Aider | CLI-invocable, richer config |
177
+ | 4 | Cursor, Copilot, Windsurf | Trivial formats, large user bases |
178
+
179
+ GPT-NeoX is a separate engine (not a model profile within Ollama) to
180
+ ensure deployment independence. Air-gapped environments may run GPT-NeoX
181
+ on vLLM, TGI, or custom inference without Ollama.
182
+
183
+ ### Q8: Migration Path
184
+
185
+ **Decision**: Incremental migration. Version bump to **1.0.0** — the
186
+ engine-agnostic architecture is the v1 identity.
187
+
188
+ Engine Phase 0 splits into three sub-phases:
189
+
190
+ - **0a**: Rename "Claude Companion" → "Code Companion", bump to 1.0.0
191
+ - **0b**: Create `engines/` directory structure, move Claude + Generic
192
+ - **0c**: XDG paths, `--engine` flag, detector framework
193
+
194
+ Each sub-phase is a separate branch and merge request. Tests pass at
195
+ every step. Existing `~/.claude/` workflows continue working — Claude
196
+ engine writes to `~/.claude/rules/` as before.
197
+
198
+ ### Q9: Priority vs Desktop Integration
199
+
200
+ **Decision**: Engine Phase 0 (restructure) lands first, then Desktop
201
+ Phase 1 (D-Bus service) starts immediately after. The two workstreams
202
+ are orthogonal — desktop integration is transport layer, engine
203
+ architecture is content layer. They can interleave after Phase 0.
204
+
205
+ ## Consequences
206
+
207
+ - ADR-006 is superseded (this ADR provides the concrete decisions it
208
+ deferred)
209
+ - `architecture.yml` must be updated to reflect engine-agnostic core
210
+ - A new design document `engine_architecture.yml` captures the engine
211
+ plugin system
212
+ - The implementation plan defines 7 engine phases and 3 desktop phases
213
+ with explicit dependencies
214
+ - All existing tests continue passing throughout the incremental
215
+ migration
216
+ - The `anthropic` gem is removed from core runtime dependencies at
217
+ Phase 0b
218
+ - Users on current `~/.claude/`-based installations experience no
219
+ breakage — the Claude engine continues to write to Claude-native paths
@@ -0,0 +1,129 @@
1
+ # ADR-008: CI Bundler Strategy and Dependency Integrity
2
+
3
+ ## Status
4
+
5
+ Accepted (2026-03-01)
6
+
7
+ ## Context
8
+
9
+ The CI pipeline uses `.ruby_base` as the shared template for all Ruby jobs.
10
+ This template runs `bundle install` in a Docker image (`ruby:3.3.10-bookworm`)
11
+ without specifying which Bundler groups to include or exclude, and without
12
+ pinning to a lockfile.
13
+
14
+ Three problems emerged:
15
+
16
+ 1. **Native build failures**: The `:desktop` Bundler group contains the
17
+ `adwaita` gem, which transitively depends on `gobject-introspection`.
18
+ That gem requires `libgirepository1.0-dev` at build time. The CI Docker
19
+ image does not include this library, and the gem's auto-install attempt
20
+ fails without root privileges. No CI job needs GTK4 gems.
21
+
22
+ 2. **Version drift**: Without a committed `Gemfile.lock`, CI resolves
23
+ dependencies fresh on each run. RuboCop `~> 1.82` resolved to 1.85.0 in
24
+ CI while developers ran 1.84.2 locally. With `NewCops: enable` in
25
+ `.rubocop.yml`, new cops in 1.85.0 produced offenses that did not exist
26
+ in the local version, causing false CI failures.
27
+
28
+ 3. **Incomplete pre-commit linting**: The built-in overcommit `RuboCop`
29
+ hook only lints files in the commit diff. When a rubocop version update
30
+ introduces new cops, offenses in unchanged files are invisible to the
31
+ pre-commit hook. The CI rubocop job catches them, but the feedback loop
32
+ is slow and indirect.
33
+
34
+ ## Decisions
35
+
36
+ ### D1: Exclude the `:desktop` group in CI
37
+
38
+ The `.ruby_base` template now runs:
39
+
40
+ ```yaml
41
+ - bundle config set --local without 'desktop'
42
+ ```
43
+
44
+ before `bundle install`. This prevents the entire GTK4 dependency chain
45
+ (`adwaita -> gtk4 -> gsk4 -> gdk4 -> gdk_pixbuf2 -> gio2 ->
46
+ gobject-introspection`) from being resolved and built in CI.
47
+
48
+ **Rationale**: No CI job requires GTK4 gems. Desktop integration testing
49
+ is deferred to a future dedicated job that would install system dependencies
50
+ and override the `without` config.
51
+
52
+ **Impact**: All jobs extending `.ruby_base` skip `:desktop` gems. If a
53
+ desktop-specific CI job is ever needed, it must override the `before_script`
54
+ to remove the `without` exclusion and install `libgirepository1.0-dev`,
55
+ `libgtk-4-dev`, and related system packages.
56
+
57
+ ### D2: Track `Gemfile.lock` and freeze CI installs
58
+
59
+ Two complementary changes:
60
+
61
+ 1. `Gemfile.lock` is removed from `.gitignore` and committed to the
62
+ repository. This captures exact resolved versions for all dependencies.
63
+
64
+ 2. The `.ruby_base` template now runs:
65
+
66
+ ```yaml
67
+ - bundle config set --local frozen true
68
+ ```
69
+
70
+ before `bundle install`. This makes CI fail immediately if the lockfile
71
+ does not match the Gemfile, preventing silent resolution to newer versions.
72
+
73
+ **Rationale**: For application-like projects (as opposed to libraries),
74
+ tracking the lockfile is standard practice. It ensures CI runs the same
75
+ versions that developers test locally. The `frozen` flag enforces this.
76
+
77
+ **Trade-off**: Developers must now run `bundle update <gem>` explicitly
78
+ and commit the updated lockfile when upgrading dependencies. This is
79
+ intentional friction that prevents accidental upgrades.
80
+
81
+ ### D3: Full-project RuboCop via custom overcommit hook
82
+
83
+ The built-in overcommit `RuboCop` hook is disabled. A custom `RubocopAll`
84
+ hook replaces it:
85
+
86
+ - **File**: `.git-hooks/pre_commit/rubocop_all.rb`
87
+ - **Behaviour**: Runs `bundle exec rubocop` against all project files, not
88
+ just changed files.
89
+ - **Config**: Same flags as the original (`--config .rubocop.yml
90
+ --force-exclusion --display-cop-names`).
91
+
92
+ **Rationale**: The per-file hook misses offenses in unchanged files. After
93
+ a rubocop upgrade introduces new cops, the pre-commit hook must catch all
94
+ offenses before they reach CI. Running rubocop on all ~245 files takes
95
+ under 10 seconds, so the performance cost is acceptable.
96
+
97
+ **Trade-off**: Every commit triggers a full rubocop scan regardless of
98
+ what changed. For the current codebase size this is negligible, but may
99
+ need revisiting if the project grows significantly.
100
+
101
+ ## Consequences
102
+
103
+ ### Positive
104
+
105
+ - CI `bundle install` no longer attempts to build native GTK4 extensions.
106
+ - All validate, code quality, security, test, and build jobs can run
107
+ without system-level GTK4 development libraries.
108
+ - CI uses identical gem versions to development, eliminating false
109
+ positives from version drift.
110
+ - Pre-commit hooks catch all rubocop offenses before code reaches CI.
111
+
112
+ ### Negative
113
+
114
+ - Developers must explicitly update the lockfile: `bundle update <gem>`
115
+ followed by committing `Gemfile.lock`.
116
+ - If a developer forgets to commit the lockfile after a Gemfile change,
117
+ CI will fail with a frozen bundle error. This is a feature, not a bug.
118
+ - Pre-commit rubocop runs take ~10 seconds per commit instead of ~1 second
119
+ (full scan vs changed files only).
120
+
121
+ ## Files
122
+
123
+ | File | Change |
124
+ |------|--------|
125
+ | `.gitlab-ci-files/global/defaults.yml` | Added `without 'desktop'` and `frozen true` to `.ruby_base` |
126
+ | `.gitignore` | Removed `Gemfile.lock` entry |
127
+ | `Gemfile.lock` | Now tracked |
128
+ | `.overcommit.yml` | Disabled `RuboCop`, added `RubocopAll` |
129
+ | `.git-hooks/pre_commit/rubocop_all.rb` | Custom overcommit hook |