anima-core 0.2.1 → 1.0.0

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 (280) hide show
  1. checksums.yaml +4 -4
  2. data/.reek.yml +27 -1
  3. data/CHANGELOG.md +19 -0
  4. data/README.md +213 -43
  5. data/agents/codebase-analyzer.md +88 -0
  6. data/agents/codebase-pattern-finder.md +83 -0
  7. data/agents/documentation-researcher.md +59 -0
  8. data/agents/thoughts-analyzer.md +102 -0
  9. data/agents/web-search-researcher.md +71 -0
  10. data/anima-core.gemspec +3 -0
  11. data/app/channels/session_channel.rb +195 -45
  12. data/app/decorators/user_message_decorator.rb +16 -5
  13. data/app/jobs/agent_request_job.rb +55 -2
  14. data/app/jobs/analytical_brain_job.rb +33 -0
  15. data/app/jobs/count_event_tokens_job.rb +15 -4
  16. data/app/models/concerns/event/broadcasting.rb +81 -0
  17. data/app/models/event.rb +20 -1
  18. data/app/models/goal.rb +91 -0
  19. data/app/models/session.rb +366 -21
  20. data/config/application.rb +2 -0
  21. data/config/initializers/event_subscribers.rb +0 -1
  22. data/config/routes.rb +0 -6
  23. data/db/migrate/20260313010000_add_status_to_events.rb +8 -0
  24. data/db/migrate/20260313020000_add_processing_to_sessions.rb +7 -0
  25. data/db/migrate/20260314075248_add_subagent_support_to_sessions.rb +6 -0
  26. data/db/migrate/20260314112417_add_granted_tools_to_sessions.rb +5 -0
  27. data/db/migrate/20260314140000_add_name_to_sessions.rb +7 -0
  28. data/db/migrate/20260314150000_add_viewport_event_ids_to_sessions.rb +7 -0
  29. data/db/migrate/20260315100000_add_active_skills_to_sessions.rb +7 -0
  30. data/db/migrate/20260315140843_create_goals.rb +16 -0
  31. data/db/migrate/20260315144837_add_completed_at_to_goals.rb +5 -0
  32. data/db/migrate/20260315191105_add_active_workflow_to_sessions.rb +5 -0
  33. data/lib/agent_loop.rb +65 -6
  34. data/lib/agents/definition.rb +116 -0
  35. data/lib/agents/registry.rb +106 -0
  36. data/lib/analytical_brain/runner.rb +276 -0
  37. data/lib/analytical_brain/tools/activate_skill.rb +52 -0
  38. data/lib/analytical_brain/tools/deactivate_skill.rb +43 -0
  39. data/lib/analytical_brain/tools/deactivate_workflow.rb +34 -0
  40. data/lib/analytical_brain/tools/everything_is_ready.rb +28 -0
  41. data/lib/analytical_brain/tools/finish_goal.rb +62 -0
  42. data/lib/analytical_brain/tools/read_workflow.rb +58 -0
  43. data/lib/analytical_brain/tools/rename_session.rb +63 -0
  44. data/lib/analytical_brain/tools/set_goal.rb +60 -0
  45. data/lib/analytical_brain/tools/update_goal.rb +60 -0
  46. data/lib/analytical_brain.rb +23 -0
  47. data/lib/anima/cli/mcp/secrets.rb +76 -0
  48. data/lib/anima/cli/mcp.rb +197 -0
  49. data/lib/anima/cli.rb +5 -40
  50. data/lib/anima/installer.rb +168 -0
  51. data/lib/anima/settings.rb +226 -0
  52. data/lib/anima/version.rb +1 -1
  53. data/lib/anima.rb +9 -0
  54. data/lib/credential_store.rb +103 -0
  55. data/lib/environment_probe.rb +232 -0
  56. data/lib/events/subscribers/persister.rb +1 -0
  57. data/lib/events/user_message.rb +17 -0
  58. data/lib/llm/client.rb +29 -10
  59. data/lib/mcp/client_manager.rb +86 -0
  60. data/lib/mcp/config.rb +213 -0
  61. data/lib/mcp/health_check.rb +77 -0
  62. data/lib/mcp/secrets.rb +73 -0
  63. data/lib/mcp/stdio_transport.rb +206 -0
  64. data/lib/providers/anthropic.rb +11 -20
  65. data/lib/shell_session.rb +11 -10
  66. data/lib/skills/definition.rb +97 -0
  67. data/lib/skills/registry.rb +105 -0
  68. data/lib/tools/edit.rb +226 -0
  69. data/lib/tools/mcp_tool.rb +114 -0
  70. data/lib/tools/read.rb +151 -0
  71. data/lib/tools/registry.rb +14 -12
  72. data/lib/tools/request_feature.rb +121 -0
  73. data/lib/tools/return_result.rb +81 -0
  74. data/lib/tools/spawn_specialist.rb +109 -0
  75. data/lib/tools/spawn_subagent.rb +111 -0
  76. data/lib/tools/subagent_prompts.rb +12 -0
  77. data/lib/tools/web_get.rb +8 -9
  78. data/lib/tools/write.rb +86 -0
  79. data/lib/tui/app.rb +985 -26
  80. data/lib/tui/cable_client.rb +69 -31
  81. data/lib/tui/message_store.rb +103 -8
  82. data/lib/tui/screens/chat.rb +293 -45
  83. data/lib/workflows/definition.rb +97 -0
  84. data/lib/workflows/registry.rb +89 -0
  85. data/skills/activerecord/SKILL.md +255 -0
  86. data/skills/activerecord/examples/associations/association_extensions.rb +298 -0
  87. data/skills/activerecord/examples/associations/basic_associations.rb +118 -0
  88. data/skills/activerecord/examples/associations/counter_caches.rb +215 -0
  89. data/skills/activerecord/examples/associations/polymorphic_associations.rb +217 -0
  90. data/skills/activerecord/examples/associations/self_referential.rb +302 -0
  91. data/skills/activerecord/examples/associations/through_associations.rb +203 -0
  92. data/skills/activerecord/examples/basics/crud_operations.rb +209 -0
  93. data/skills/activerecord/examples/basics/dirty_tracking.rb +218 -0
  94. data/skills/activerecord/examples/basics/inheritance.rb +377 -0
  95. data/skills/activerecord/examples/basics/type_casting.rb +317 -0
  96. data/skills/activerecord/examples/callbacks/alternatives_to_callbacks.rb +447 -0
  97. data/skills/activerecord/examples/callbacks/conditional_callbacks.rb +353 -0
  98. data/skills/activerecord/examples/callbacks/lifecycle_callbacks.rb +280 -0
  99. data/skills/activerecord/examples/callbacks/transaction_callbacks.rb +340 -0
  100. data/skills/activerecord/examples/migrations/indexes_and_constraints.rb +337 -0
  101. data/skills/activerecord/examples/migrations/reversible_patterns.rb +403 -0
  102. data/skills/activerecord/examples/migrations/safe_patterns.rb +420 -0
  103. data/skills/activerecord/examples/migrations/schema_changes.rb +277 -0
  104. data/skills/activerecord/examples/querying/batch_processing.rb +226 -0
  105. data/skills/activerecord/examples/querying/eager_loading.rb +259 -0
  106. data/skills/activerecord/examples/querying/finder_methods.rb +170 -0
  107. data/skills/activerecord/examples/querying/optimization.rb +275 -0
  108. data/skills/activerecord/examples/querying/scopes.rb +260 -0
  109. data/skills/activerecord/examples/validations/built_in_validators.rb +277 -0
  110. data/skills/activerecord/examples/validations/conditional_validations.rb +288 -0
  111. data/skills/activerecord/examples/validations/custom_validators.rb +381 -0
  112. data/skills/activerecord/examples/validations/database_constraints.rb +432 -0
  113. data/skills/activerecord/examples/validations/validation_contexts.rb +367 -0
  114. data/skills/activerecord/references/associations.md +709 -0
  115. data/skills/activerecord/references/basics.md +622 -0
  116. data/skills/activerecord/references/callbacks.md +738 -0
  117. data/skills/activerecord/references/migrations.md +657 -0
  118. data/skills/activerecord/references/querying.md +655 -0
  119. data/skills/activerecord/references/validations.md +596 -0
  120. data/skills/dragonruby/SKILL.md +250 -0
  121. data/skills/dragonruby/examples/audio/audio_events.rb +55 -0
  122. data/skills/dragonruby/examples/audio/background_music.rb +29 -0
  123. data/skills/dragonruby/examples/audio/crossfade.rb +51 -0
  124. data/skills/dragonruby/examples/audio/music_controls.rb +51 -0
  125. data/skills/dragonruby/examples/audio/sound_effects.rb +30 -0
  126. data/skills/dragonruby/examples/core/coordinate_system.rb +27 -0
  127. data/skills/dragonruby/examples/core/hello_world.rb +24 -0
  128. data/skills/dragonruby/examples/core/labels.rb +22 -0
  129. data/skills/dragonruby/examples/core/sprites.rb +35 -0
  130. data/skills/dragonruby/examples/core/state_management.rb +29 -0
  131. data/skills/dragonruby/examples/distribution/background_pause.rb +42 -0
  132. data/skills/dragonruby/examples/distribution/build_workflow.sh +26 -0
  133. data/skills/dragonruby/examples/distribution/cvars_production.txt +16 -0
  134. data/skills/dragonruby/examples/distribution/game_metadata_hd.txt +23 -0
  135. data/skills/dragonruby/examples/distribution/game_metadata_minimal.txt +9 -0
  136. data/skills/dragonruby/examples/distribution/game_metadata_mobile.txt +31 -0
  137. data/skills/dragonruby/examples/distribution/platform_detection.rb +36 -0
  138. data/skills/dragonruby/examples/distribution/steam_metadata.txt +19 -0
  139. data/skills/dragonruby/examples/entities/collision_detection.rb +43 -0
  140. data/skills/dragonruby/examples/entities/entity_lifecycle.rb +68 -0
  141. data/skills/dragonruby/examples/entities/entity_storage.rb +38 -0
  142. data/skills/dragonruby/examples/entities/factory_methods.rb +45 -0
  143. data/skills/dragonruby/examples/entities/random_spawning.rb +50 -0
  144. data/skills/dragonruby/examples/game-logic/reset_patterns.rb +98 -0
  145. data/skills/dragonruby/examples/game-logic/save_load.rb +101 -0
  146. data/skills/dragonruby/examples/game-logic/scoring.rb +104 -0
  147. data/skills/dragonruby/examples/game-logic/state_transitions.rb +103 -0
  148. data/skills/dragonruby/examples/game-logic/timers.rb +87 -0
  149. data/skills/dragonruby/examples/input/action_triggers.rb +36 -0
  150. data/skills/dragonruby/examples/input/analog_movement.rb +28 -0
  151. data/skills/dragonruby/examples/input/controller_input.rb +28 -0
  152. data/skills/dragonruby/examples/input/directional_input.rb +24 -0
  153. data/skills/dragonruby/examples/input/keyboard_input.rb +28 -0
  154. data/skills/dragonruby/examples/input/mouse_click.rb +26 -0
  155. data/skills/dragonruby/examples/input/movement_with_bounds.rb +22 -0
  156. data/skills/dragonruby/examples/input/normalized_movement.rb +32 -0
  157. data/skills/dragonruby/examples/rendering/frame_animation.rb +32 -0
  158. data/skills/dragonruby/examples/rendering/labels.rb +32 -0
  159. data/skills/dragonruby/examples/rendering/layering.rb +51 -0
  160. data/skills/dragonruby/examples/rendering/solids.rb +61 -0
  161. data/skills/dragonruby/examples/rendering/sprites.rb +33 -0
  162. data/skills/dragonruby/examples/rendering/spritesheet_animation.rb +39 -0
  163. data/skills/dragonruby/examples/scenes/case_dispatch.rb +60 -0
  164. data/skills/dragonruby/examples/scenes/class_based.rb +150 -0
  165. data/skills/dragonruby/examples/scenes/pause_overlay.rb +100 -0
  166. data/skills/dragonruby/examples/scenes/safe_transitions.rb +68 -0
  167. data/skills/dragonruby/examples/scenes/scene_transitions.rb +98 -0
  168. data/skills/dragonruby/examples/scenes/send_dispatch.rb +88 -0
  169. data/skills/dragonruby/references/audio.md +396 -0
  170. data/skills/dragonruby/references/core.md +385 -0
  171. data/skills/dragonruby/references/distribution.md +434 -0
  172. data/skills/dragonruby/references/entities.md +516 -0
  173. data/skills/dragonruby/references/game-logic/persistence.md +386 -0
  174. data/skills/dragonruby/references/game-logic/state.md +389 -0
  175. data/skills/dragonruby/references/input.md +414 -0
  176. data/skills/dragonruby/references/rendering/animation.md +467 -0
  177. data/skills/dragonruby/references/rendering/primitives.md +403 -0
  178. data/skills/dragonruby/references/scenes.md +443 -0
  179. data/skills/draper-decorators/SKILL.md +344 -0
  180. data/skills/draper-decorators/examples/application_decorator.rb +61 -0
  181. data/skills/draper-decorators/examples/decorator_spec.rb +253 -0
  182. data/skills/draper-decorators/examples/model_decorator.rb +152 -0
  183. data/skills/draper-decorators/references/anti-patterns.md +640 -0
  184. data/skills/draper-decorators/references/patterns.md +507 -0
  185. data/skills/draper-decorators/references/testing.md +559 -0
  186. data/skills/gh-issue.md +182 -0
  187. data/skills/mcp-server/SKILL.md +177 -0
  188. data/skills/mcp-server/examples/dynamic_tools.rb +36 -0
  189. data/skills/mcp-server/examples/file_manager_tool.rb +85 -0
  190. data/skills/mcp-server/examples/http_client.rb +48 -0
  191. data/skills/mcp-server/examples/http_server.rb +97 -0
  192. data/skills/mcp-server/examples/rails_integration.rb +88 -0
  193. data/skills/mcp-server/examples/stdio_server.rb +108 -0
  194. data/skills/mcp-server/examples/streaming_client.rb +95 -0
  195. data/skills/mcp-server/references/gotchas.md +183 -0
  196. data/skills/mcp-server/references/prompts.md +98 -0
  197. data/skills/mcp-server/references/resources.md +53 -0
  198. data/skills/mcp-server/references/server.md +140 -0
  199. data/skills/mcp-server/references/tools.md +146 -0
  200. data/skills/mcp-server/references/transport.md +104 -0
  201. data/skills/ratatui-ruby/SKILL.md +315 -0
  202. data/skills/ratatui-ruby/references/core-concepts.md +340 -0
  203. data/skills/ratatui-ruby/references/events.md +387 -0
  204. data/skills/ratatui-ruby/references/frameworks.md +522 -0
  205. data/skills/ratatui-ruby/references/layout.md +423 -0
  206. data/skills/ratatui-ruby/references/styling.md +268 -0
  207. data/skills/ratatui-ruby/references/testing.md +433 -0
  208. data/skills/ratatui-ruby/references/widgets.md +532 -0
  209. data/skills/rspec/SKILL.md +340 -0
  210. data/skills/rspec/examples/core/basic_structure.rb +69 -0
  211. data/skills/rspec/examples/core/configuration.rb +126 -0
  212. data/skills/rspec/examples/core/hooks.rb +126 -0
  213. data/skills/rspec/examples/core/memoized_helpers.rb +139 -0
  214. data/skills/rspec/examples/core/metadata_filtering.rb +144 -0
  215. data/skills/rspec/examples/core/shared_examples.rb +145 -0
  216. data/skills/rspec/examples/factory_bot/associations.rb +314 -0
  217. data/skills/rspec/examples/factory_bot/build_strategies.rb +272 -0
  218. data/skills/rspec/examples/factory_bot/callbacks.rb +320 -0
  219. data/skills/rspec/examples/factory_bot/custom_construction.rb +328 -0
  220. data/skills/rspec/examples/factory_bot/factory_definition.rb +191 -0
  221. data/skills/rspec/examples/factory_bot/inheritance.rb +314 -0
  222. data/skills/rspec/examples/factory_bot/traits.rb +293 -0
  223. data/skills/rspec/examples/factory_bot/transients.rb +229 -0
  224. data/skills/rspec/examples/matchers/change.rb +115 -0
  225. data/skills/rspec/examples/matchers/collections.rb +154 -0
  226. data/skills/rspec/examples/matchers/comparisons.rb +79 -0
  227. data/skills/rspec/examples/matchers/composing.rb +155 -0
  228. data/skills/rspec/examples/matchers/custom_matchers.rb +197 -0
  229. data/skills/rspec/examples/matchers/equality.rb +58 -0
  230. data/skills/rspec/examples/matchers/errors.rb +136 -0
  231. data/skills/rspec/examples/matchers/output.rb +103 -0
  232. data/skills/rspec/examples/matchers/predicates.rb +87 -0
  233. data/skills/rspec/examples/matchers/truthiness.rb +101 -0
  234. data/skills/rspec/examples/matchers/types.rb +82 -0
  235. data/skills/rspec/examples/matchers/yield.rb +147 -0
  236. data/skills/rspec/examples/mocks/any_instance.rb +172 -0
  237. data/skills/rspec/examples/mocks/argument_matchers.rb +206 -0
  238. data/skills/rspec/examples/mocks/constants.rb +177 -0
  239. data/skills/rspec/examples/mocks/doubles.rb +139 -0
  240. data/skills/rspec/examples/mocks/expectations.rb +137 -0
  241. data/skills/rspec/examples/mocks/message_chains.rb +173 -0
  242. data/skills/rspec/examples/mocks/ordering.rb +144 -0
  243. data/skills/rspec/examples/mocks/receive_counts.rb +181 -0
  244. data/skills/rspec/examples/mocks/responses.rb +223 -0
  245. data/skills/rspec/examples/mocks/spies.rb +149 -0
  246. data/skills/rspec/examples/mocks/stubbing.rb +133 -0
  247. data/skills/rspec/examples/rails/channels.rb +250 -0
  248. data/skills/rspec/examples/rails/controller_specs.rb +302 -0
  249. data/skills/rspec/examples/rails/helper_specs.rb +245 -0
  250. data/skills/rspec/examples/rails/job_specs.rb +256 -0
  251. data/skills/rspec/examples/rails/mailer_specs.rb +228 -0
  252. data/skills/rspec/examples/rails/matchers.rb +374 -0
  253. data/skills/rspec/examples/rails/model_specs.rb +193 -0
  254. data/skills/rspec/examples/rails/request_specs.rb +275 -0
  255. data/skills/rspec/examples/rails/routing_specs.rb +276 -0
  256. data/skills/rspec/examples/rails/system_specs.rb +294 -0
  257. data/skills/rspec/examples/rails/transactions.rb +254 -0
  258. data/skills/rspec/examples/rails/view_specs.rb +252 -0
  259. data/skills/rspec/references/core.md +816 -0
  260. data/skills/rspec/references/factory_bot.md +641 -0
  261. data/skills/rspec/references/matchers.md +516 -0
  262. data/skills/rspec/references/mocks.md +381 -0
  263. data/skills/rspec/references/rails.md +528 -0
  264. data/templates/soul.md +40 -0
  265. data/workflows/commit.md +45 -0
  266. data/workflows/create_handoff.md +98 -0
  267. data/workflows/create_note.md +82 -0
  268. data/workflows/create_plan.md +457 -0
  269. data/workflows/decompose_ticket.md +109 -0
  270. data/workflows/feature.md +91 -0
  271. data/workflows/implement_plan.md +87 -0
  272. data/workflows/iterate_plan.md +247 -0
  273. data/workflows/research_codebase.md +210 -0
  274. data/workflows/resume_handoff.md +217 -0
  275. data/workflows/review_pr.md +320 -0
  276. data/workflows/thoughts_init.md +71 -0
  277. data/workflows/validate_plan.md +166 -0
  278. metadata +290 -3
  279. data/app/controllers/api/sessions_controller.rb +0 -25
  280. data/lib/events/subscribers/action_cable_bridge.rb +0 -59
@@ -0,0 +1,166 @@
1
+ ---
2
+ name: validate_plan
3
+ description: "Validate implementation against plan, verify success criteria, and identify issues."
4
+ ---
5
+
6
+ # Validate Plan
7
+
8
+ You are tasked with validating that an implementation plan was correctly executed, verifying all success criteria and identifying any deviations or issues.
9
+
10
+ ## Initial Setup
11
+
12
+ When invoked:
13
+ 1. **Determine context** - Are you in an existing conversation or starting fresh?
14
+ - If existing: Review what was implemented in this session
15
+ - If fresh: Need to discover what was done through git and codebase analysis
16
+
17
+ 2. **Locate the plan**:
18
+ - If plan path provided, use it
19
+ - Otherwise, search recent commits for plan references or ask user
20
+
21
+ 3. **Gather implementation evidence**:
22
+ ```bash
23
+ # Check recent commits
24
+ git log --oneline -n 20
25
+ git diff HEAD~N..HEAD # Where N covers implementation commits
26
+
27
+ # Run comprehensive checks
28
+ cd $(git rev-parse --show-toplevel) && make check test
29
+ ```
30
+
31
+ ## Validation Process
32
+
33
+ ### Step 1: Context Discovery
34
+
35
+ If starting fresh or need more context:
36
+
37
+ 1. **Read the implementation plan** completely
38
+ 2. **Identify what should have changed**:
39
+ - List all files that should be modified
40
+ - Note all success criteria (automated and manual)
41
+ - Identify key functionality to verify
42
+
43
+ 3. **Spawn parallel research tasks** to discover implementation:
44
+ ```
45
+ Task 1 - Verify database changes:
46
+ Research if migration [N] was added and schema changes match plan.
47
+ Check: migration files, schema version, table structure
48
+ Return: What was implemented vs what plan specified
49
+
50
+ Task 2 - Verify code changes:
51
+ Find all modified files related to [feature].
52
+ Compare actual changes to plan specifications.
53
+ Return: File-by-file comparison of planned vs actual
54
+
55
+ Task 3 - Verify test coverage:
56
+ Check if tests were added/modified as specified.
57
+ Run test commands and capture results.
58
+ Return: Test status and any missing coverage
59
+ ```
60
+
61
+ ### Step 2: Systematic Validation
62
+
63
+ For each phase in the plan:
64
+
65
+ 1. **Check completion status**:
66
+ - Look for checkmarks in the plan (- [x])
67
+ - Verify the actual code matches claimed completion
68
+
69
+ 2. **Run automated verification**:
70
+ - Execute each command from "Automated Verification"
71
+ - Document pass/fail status
72
+ - If failures, investigate root cause
73
+
74
+ 3. **Assess manual criteria**:
75
+ - List what needs manual testing
76
+ - Provide clear steps for user verification
77
+
78
+ 4. **Think deeply about edge cases**:
79
+ - Were error conditions handled?
80
+ - Are there missing validations?
81
+ - Could the implementation break existing functionality?
82
+
83
+ ### Step 3: Generate Validation Report
84
+
85
+ Create comprehensive validation summary:
86
+
87
+ ```markdown
88
+ ## Validation Report: [Plan Name]
89
+
90
+ ### Implementation Status
91
+ ✓ Phase 1: [Name] - Fully implemented
92
+ ✓ Phase 2: [Name] - Fully implemented
93
+ ⚠️ Phase 3: [Name] - Partially implemented (see issues)
94
+
95
+ ### Automated Verification Results
96
+ ✓ Build passes: `make build`
97
+ ✓ Tests pass: `make test`
98
+ ✗ Linting issues: `make lint` (3 warnings)
99
+
100
+ ### Code Review Findings
101
+
102
+ #### Matches Plan:
103
+ - Database migration correctly adds [table]
104
+ - API endpoints implement specified methods
105
+ - Error handling follows plan
106
+
107
+ #### Deviations from Plan:
108
+ - Used different variable names in [file:line]
109
+ - Added extra validation in [file:line] (improvement)
110
+
111
+ #### Potential Issues:
112
+ - Missing index on foreign key could impact performance
113
+ - No rollback handling in migration
114
+
115
+ ### Manual Testing Required:
116
+ 1. UI functionality:
117
+ - [ ] Verify [feature] appears correctly
118
+ - [ ] Test error states with invalid input
119
+
120
+ 2. Integration:
121
+ - [ ] Confirm works with existing [component]
122
+ - [ ] Check performance with large datasets
123
+
124
+ ### Recommendations:
125
+ - Address linting warnings before merge
126
+ - Consider adding integration test for [scenario]
127
+ - Document new API endpoints
128
+ ```
129
+
130
+ ## Working with Existing Context
131
+
132
+ If you were part of the implementation:
133
+ - Review the conversation history
134
+ - Check your todo list for what was completed
135
+ - Focus validation on work done in this session
136
+ - Be honest about any shortcuts or incomplete items
137
+
138
+ ## Important Guidelines
139
+
140
+ 1. **Be thorough but practical** - Focus on what matters
141
+ 2. **Run all automated checks** - Don't skip verification commands
142
+ 3. **Document everything** - Both successes and issues
143
+ 4. **Think critically** - Question if the implementation truly solves the problem
144
+ 5. **Consider maintenance** - Will this be maintainable long-term?
145
+
146
+ ## Validation Checklist
147
+
148
+ Always verify:
149
+ - [ ] All phases marked complete are actually done
150
+ - [ ] Automated tests pass
151
+ - [ ] Code follows existing patterns
152
+ - [ ] No regressions introduced
153
+ - [ ] Error handling is robust
154
+ - [ ] Documentation updated if needed
155
+ - [ ] Manual test steps are clear
156
+
157
+ ## Relationship to Other Commands
158
+
159
+ Recommended workflow:
160
+ 1. `implement_plan` — Execute the implementation
161
+ 2. `commit` — Create atomic commits for changes
162
+ 3. `validate_plan` — Verify implementation correctness
163
+
164
+ The validation works best after commits are made, as it can analyze the git history to understand what was implemented.
165
+
166
+ Remember: Good validation catches issues before they reach production. Be constructive but thorough in identifying gaps or improvements.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anima-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yevhenii Hurin
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '4.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: foreman
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -51,6 +65,20 @@ dependencies:
51
65
  - - "~>"
52
66
  - !ruby/object:Gem::Version
53
67
  version: '0.24'
68
+ - !ruby/object:Gem::Dependency
69
+ name: mcp
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.8'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.8'
54
82
  - !ruby/object:Gem::Dependency
55
83
  name: puma
56
84
  requirement: !ruby/object:Gem::Requirement
@@ -135,6 +163,20 @@ dependencies:
135
163
  - - "~>"
136
164
  - !ruby/object:Gem::Version
137
165
  version: '2.0'
166
+ - !ruby/object:Gem::Dependency
167
+ name: toml-rb
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '4.0'
173
+ type: :runtime
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: '4.0'
138
180
  - !ruby/object:Gem::Dependency
139
181
  name: websocket-client-simple
140
182
  requirement: !ruby/object:Gem::Requirement
@@ -165,11 +207,15 @@ files:
165
207
  - Procfile.dev
166
208
  - README.md
167
209
  - Rakefile
210
+ - agents/codebase-analyzer.md
211
+ - agents/codebase-pattern-finder.md
212
+ - agents/documentation-researcher.md
213
+ - agents/thoughts-analyzer.md
214
+ - agents/web-search-researcher.md
168
215
  - anima-core.gemspec
169
216
  - app/channels/application_cable/channel.rb
170
217
  - app/channels/application_cable/connection.rb
171
218
  - app/channels/session_channel.rb
172
- - app/controllers/api/sessions_controller.rb
173
219
  - app/controllers/application_controller.rb
174
220
  - app/decorators/agent_message_decorator.rb
175
221
  - app/decorators/application_decorator.rb
@@ -179,10 +225,13 @@ files:
179
225
  - app/decorators/tool_response_decorator.rb
180
226
  - app/decorators/user_message_decorator.rb
181
227
  - app/jobs/agent_request_job.rb
228
+ - app/jobs/analytical_brain_job.rb
182
229
  - app/jobs/application_job.rb
183
230
  - app/jobs/count_event_tokens_job.rb
184
231
  - app/models/application_record.rb
232
+ - app/models/concerns/event/broadcasting.rb
185
233
  - app/models/event.rb
234
+ - app/models/goal.rb
186
235
  - app/models/session.rb
187
236
  - bin/jobs
188
237
  - bin/rails
@@ -211,19 +260,46 @@ files:
211
260
  - db/migrate/20260308150000_add_token_count_to_events.rb
212
261
  - db/migrate/20260308160000_add_tool_use_id_to_events.rb
213
262
  - db/migrate/20260312170000_add_view_mode_to_sessions.rb
263
+ - db/migrate/20260313010000_add_status_to_events.rb
264
+ - db/migrate/20260313020000_add_processing_to_sessions.rb
265
+ - db/migrate/20260314075248_add_subagent_support_to_sessions.rb
266
+ - db/migrate/20260314112417_add_granted_tools_to_sessions.rb
267
+ - db/migrate/20260314140000_add_name_to_sessions.rb
268
+ - db/migrate/20260314150000_add_viewport_event_ids_to_sessions.rb
269
+ - db/migrate/20260315100000_add_active_skills_to_sessions.rb
270
+ - db/migrate/20260315140843_create_goals.rb
271
+ - db/migrate/20260315144837_add_completed_at_to_goals.rb
272
+ - db/migrate/20260315191105_add_active_workflow_to_sessions.rb
214
273
  - db/queue_schema.rb
215
274
  - db/seeds.rb
216
275
  - exe/anima
217
276
  - lib/agent_loop.rb
277
+ - lib/agents/definition.rb
278
+ - lib/agents/registry.rb
279
+ - lib/analytical_brain.rb
280
+ - lib/analytical_brain/runner.rb
281
+ - lib/analytical_brain/tools/activate_skill.rb
282
+ - lib/analytical_brain/tools/deactivate_skill.rb
283
+ - lib/analytical_brain/tools/deactivate_workflow.rb
284
+ - lib/analytical_brain/tools/everything_is_ready.rb
285
+ - lib/analytical_brain/tools/finish_goal.rb
286
+ - lib/analytical_brain/tools/read_workflow.rb
287
+ - lib/analytical_brain/tools/rename_session.rb
288
+ - lib/analytical_brain/tools/set_goal.rb
289
+ - lib/analytical_brain/tools/update_goal.rb
218
290
  - lib/anima.rb
219
291
  - lib/anima/cli.rb
292
+ - lib/anima/cli/mcp.rb
293
+ - lib/anima/cli/mcp/secrets.rb
220
294
  - lib/anima/installer.rb
295
+ - lib/anima/settings.rb
221
296
  - lib/anima/version.rb
297
+ - lib/credential_store.rb
298
+ - lib/environment_probe.rb
222
299
  - lib/events/agent_message.rb
223
300
  - lib/events/base.rb
224
301
  - lib/events/bus.rb
225
302
  - lib/events/subscriber.rb
226
- - lib/events/subscribers/action_cable_bridge.rb
227
303
  - lib/events/subscribers/message_collector.rb
228
304
  - lib/events/subscribers/persister.rb
229
305
  - lib/events/system_message.rb
@@ -231,17 +307,228 @@ files:
231
307
  - lib/events/tool_response.rb
232
308
  - lib/events/user_message.rb
233
309
  - lib/llm/client.rb
310
+ - lib/mcp/client_manager.rb
311
+ - lib/mcp/config.rb
312
+ - lib/mcp/health_check.rb
313
+ - lib/mcp/secrets.rb
314
+ - lib/mcp/stdio_transport.rb
234
315
  - lib/providers/anthropic.rb
235
316
  - lib/shell_session.rb
317
+ - lib/skills/definition.rb
318
+ - lib/skills/registry.rb
236
319
  - lib/tools/base.rb
237
320
  - lib/tools/bash.rb
321
+ - lib/tools/edit.rb
322
+ - lib/tools/mcp_tool.rb
323
+ - lib/tools/read.rb
238
324
  - lib/tools/registry.rb
325
+ - lib/tools/request_feature.rb
326
+ - lib/tools/return_result.rb
327
+ - lib/tools/spawn_specialist.rb
328
+ - lib/tools/spawn_subagent.rb
329
+ - lib/tools/subagent_prompts.rb
239
330
  - lib/tools/web_get.rb
331
+ - lib/tools/write.rb
240
332
  - lib/tui/app.rb
241
333
  - lib/tui/cable_client.rb
242
334
  - lib/tui/input_buffer.rb
243
335
  - lib/tui/message_store.rb
244
336
  - lib/tui/screens/chat.rb
337
+ - lib/workflows/definition.rb
338
+ - lib/workflows/registry.rb
339
+ - skills/activerecord/SKILL.md
340
+ - skills/activerecord/examples/associations/association_extensions.rb
341
+ - skills/activerecord/examples/associations/basic_associations.rb
342
+ - skills/activerecord/examples/associations/counter_caches.rb
343
+ - skills/activerecord/examples/associations/polymorphic_associations.rb
344
+ - skills/activerecord/examples/associations/self_referential.rb
345
+ - skills/activerecord/examples/associations/through_associations.rb
346
+ - skills/activerecord/examples/basics/crud_operations.rb
347
+ - skills/activerecord/examples/basics/dirty_tracking.rb
348
+ - skills/activerecord/examples/basics/inheritance.rb
349
+ - skills/activerecord/examples/basics/type_casting.rb
350
+ - skills/activerecord/examples/callbacks/alternatives_to_callbacks.rb
351
+ - skills/activerecord/examples/callbacks/conditional_callbacks.rb
352
+ - skills/activerecord/examples/callbacks/lifecycle_callbacks.rb
353
+ - skills/activerecord/examples/callbacks/transaction_callbacks.rb
354
+ - skills/activerecord/examples/migrations/indexes_and_constraints.rb
355
+ - skills/activerecord/examples/migrations/reversible_patterns.rb
356
+ - skills/activerecord/examples/migrations/safe_patterns.rb
357
+ - skills/activerecord/examples/migrations/schema_changes.rb
358
+ - skills/activerecord/examples/querying/batch_processing.rb
359
+ - skills/activerecord/examples/querying/eager_loading.rb
360
+ - skills/activerecord/examples/querying/finder_methods.rb
361
+ - skills/activerecord/examples/querying/optimization.rb
362
+ - skills/activerecord/examples/querying/scopes.rb
363
+ - skills/activerecord/examples/validations/built_in_validators.rb
364
+ - skills/activerecord/examples/validations/conditional_validations.rb
365
+ - skills/activerecord/examples/validations/custom_validators.rb
366
+ - skills/activerecord/examples/validations/database_constraints.rb
367
+ - skills/activerecord/examples/validations/validation_contexts.rb
368
+ - skills/activerecord/references/associations.md
369
+ - skills/activerecord/references/basics.md
370
+ - skills/activerecord/references/callbacks.md
371
+ - skills/activerecord/references/migrations.md
372
+ - skills/activerecord/references/querying.md
373
+ - skills/activerecord/references/validations.md
374
+ - skills/dragonruby/SKILL.md
375
+ - skills/dragonruby/examples/audio/audio_events.rb
376
+ - skills/dragonruby/examples/audio/background_music.rb
377
+ - skills/dragonruby/examples/audio/crossfade.rb
378
+ - skills/dragonruby/examples/audio/music_controls.rb
379
+ - skills/dragonruby/examples/audio/sound_effects.rb
380
+ - skills/dragonruby/examples/core/coordinate_system.rb
381
+ - skills/dragonruby/examples/core/hello_world.rb
382
+ - skills/dragonruby/examples/core/labels.rb
383
+ - skills/dragonruby/examples/core/sprites.rb
384
+ - skills/dragonruby/examples/core/state_management.rb
385
+ - skills/dragonruby/examples/distribution/background_pause.rb
386
+ - skills/dragonruby/examples/distribution/build_workflow.sh
387
+ - skills/dragonruby/examples/distribution/cvars_production.txt
388
+ - skills/dragonruby/examples/distribution/game_metadata_hd.txt
389
+ - skills/dragonruby/examples/distribution/game_metadata_minimal.txt
390
+ - skills/dragonruby/examples/distribution/game_metadata_mobile.txt
391
+ - skills/dragonruby/examples/distribution/platform_detection.rb
392
+ - skills/dragonruby/examples/distribution/steam_metadata.txt
393
+ - skills/dragonruby/examples/entities/collision_detection.rb
394
+ - skills/dragonruby/examples/entities/entity_lifecycle.rb
395
+ - skills/dragonruby/examples/entities/entity_storage.rb
396
+ - skills/dragonruby/examples/entities/factory_methods.rb
397
+ - skills/dragonruby/examples/entities/random_spawning.rb
398
+ - skills/dragonruby/examples/game-logic/reset_patterns.rb
399
+ - skills/dragonruby/examples/game-logic/save_load.rb
400
+ - skills/dragonruby/examples/game-logic/scoring.rb
401
+ - skills/dragonruby/examples/game-logic/state_transitions.rb
402
+ - skills/dragonruby/examples/game-logic/timers.rb
403
+ - skills/dragonruby/examples/input/action_triggers.rb
404
+ - skills/dragonruby/examples/input/analog_movement.rb
405
+ - skills/dragonruby/examples/input/controller_input.rb
406
+ - skills/dragonruby/examples/input/directional_input.rb
407
+ - skills/dragonruby/examples/input/keyboard_input.rb
408
+ - skills/dragonruby/examples/input/mouse_click.rb
409
+ - skills/dragonruby/examples/input/movement_with_bounds.rb
410
+ - skills/dragonruby/examples/input/normalized_movement.rb
411
+ - skills/dragonruby/examples/rendering/frame_animation.rb
412
+ - skills/dragonruby/examples/rendering/labels.rb
413
+ - skills/dragonruby/examples/rendering/layering.rb
414
+ - skills/dragonruby/examples/rendering/solids.rb
415
+ - skills/dragonruby/examples/rendering/sprites.rb
416
+ - skills/dragonruby/examples/rendering/spritesheet_animation.rb
417
+ - skills/dragonruby/examples/scenes/case_dispatch.rb
418
+ - skills/dragonruby/examples/scenes/class_based.rb
419
+ - skills/dragonruby/examples/scenes/pause_overlay.rb
420
+ - skills/dragonruby/examples/scenes/safe_transitions.rb
421
+ - skills/dragonruby/examples/scenes/scene_transitions.rb
422
+ - skills/dragonruby/examples/scenes/send_dispatch.rb
423
+ - skills/dragonruby/references/audio.md
424
+ - skills/dragonruby/references/core.md
425
+ - skills/dragonruby/references/distribution.md
426
+ - skills/dragonruby/references/entities.md
427
+ - skills/dragonruby/references/game-logic/persistence.md
428
+ - skills/dragonruby/references/game-logic/state.md
429
+ - skills/dragonruby/references/input.md
430
+ - skills/dragonruby/references/rendering/animation.md
431
+ - skills/dragonruby/references/rendering/primitives.md
432
+ - skills/dragonruby/references/scenes.md
433
+ - skills/draper-decorators/SKILL.md
434
+ - skills/draper-decorators/examples/application_decorator.rb
435
+ - skills/draper-decorators/examples/decorator_spec.rb
436
+ - skills/draper-decorators/examples/model_decorator.rb
437
+ - skills/draper-decorators/references/anti-patterns.md
438
+ - skills/draper-decorators/references/patterns.md
439
+ - skills/draper-decorators/references/testing.md
440
+ - skills/gh-issue.md
441
+ - skills/mcp-server/SKILL.md
442
+ - skills/mcp-server/examples/dynamic_tools.rb
443
+ - skills/mcp-server/examples/file_manager_tool.rb
444
+ - skills/mcp-server/examples/http_client.rb
445
+ - skills/mcp-server/examples/http_server.rb
446
+ - skills/mcp-server/examples/rails_integration.rb
447
+ - skills/mcp-server/examples/stdio_server.rb
448
+ - skills/mcp-server/examples/streaming_client.rb
449
+ - skills/mcp-server/references/gotchas.md
450
+ - skills/mcp-server/references/prompts.md
451
+ - skills/mcp-server/references/resources.md
452
+ - skills/mcp-server/references/server.md
453
+ - skills/mcp-server/references/tools.md
454
+ - skills/mcp-server/references/transport.md
455
+ - skills/ratatui-ruby/SKILL.md
456
+ - skills/ratatui-ruby/references/core-concepts.md
457
+ - skills/ratatui-ruby/references/events.md
458
+ - skills/ratatui-ruby/references/frameworks.md
459
+ - skills/ratatui-ruby/references/layout.md
460
+ - skills/ratatui-ruby/references/styling.md
461
+ - skills/ratatui-ruby/references/testing.md
462
+ - skills/ratatui-ruby/references/widgets.md
463
+ - skills/rspec/SKILL.md
464
+ - skills/rspec/examples/core/basic_structure.rb
465
+ - skills/rspec/examples/core/configuration.rb
466
+ - skills/rspec/examples/core/hooks.rb
467
+ - skills/rspec/examples/core/memoized_helpers.rb
468
+ - skills/rspec/examples/core/metadata_filtering.rb
469
+ - skills/rspec/examples/core/shared_examples.rb
470
+ - skills/rspec/examples/factory_bot/associations.rb
471
+ - skills/rspec/examples/factory_bot/build_strategies.rb
472
+ - skills/rspec/examples/factory_bot/callbacks.rb
473
+ - skills/rspec/examples/factory_bot/custom_construction.rb
474
+ - skills/rspec/examples/factory_bot/factory_definition.rb
475
+ - skills/rspec/examples/factory_bot/inheritance.rb
476
+ - skills/rspec/examples/factory_bot/traits.rb
477
+ - skills/rspec/examples/factory_bot/transients.rb
478
+ - skills/rspec/examples/matchers/change.rb
479
+ - skills/rspec/examples/matchers/collections.rb
480
+ - skills/rspec/examples/matchers/comparisons.rb
481
+ - skills/rspec/examples/matchers/composing.rb
482
+ - skills/rspec/examples/matchers/custom_matchers.rb
483
+ - skills/rspec/examples/matchers/equality.rb
484
+ - skills/rspec/examples/matchers/errors.rb
485
+ - skills/rspec/examples/matchers/output.rb
486
+ - skills/rspec/examples/matchers/predicates.rb
487
+ - skills/rspec/examples/matchers/truthiness.rb
488
+ - skills/rspec/examples/matchers/types.rb
489
+ - skills/rspec/examples/matchers/yield.rb
490
+ - skills/rspec/examples/mocks/any_instance.rb
491
+ - skills/rspec/examples/mocks/argument_matchers.rb
492
+ - skills/rspec/examples/mocks/constants.rb
493
+ - skills/rspec/examples/mocks/doubles.rb
494
+ - skills/rspec/examples/mocks/expectations.rb
495
+ - skills/rspec/examples/mocks/message_chains.rb
496
+ - skills/rspec/examples/mocks/ordering.rb
497
+ - skills/rspec/examples/mocks/receive_counts.rb
498
+ - skills/rspec/examples/mocks/responses.rb
499
+ - skills/rspec/examples/mocks/spies.rb
500
+ - skills/rspec/examples/mocks/stubbing.rb
501
+ - skills/rspec/examples/rails/channels.rb
502
+ - skills/rspec/examples/rails/controller_specs.rb
503
+ - skills/rspec/examples/rails/helper_specs.rb
504
+ - skills/rspec/examples/rails/job_specs.rb
505
+ - skills/rspec/examples/rails/mailer_specs.rb
506
+ - skills/rspec/examples/rails/matchers.rb
507
+ - skills/rspec/examples/rails/model_specs.rb
508
+ - skills/rspec/examples/rails/request_specs.rb
509
+ - skills/rspec/examples/rails/routing_specs.rb
510
+ - skills/rspec/examples/rails/system_specs.rb
511
+ - skills/rspec/examples/rails/transactions.rb
512
+ - skills/rspec/examples/rails/view_specs.rb
513
+ - skills/rspec/references/core.md
514
+ - skills/rspec/references/factory_bot.md
515
+ - skills/rspec/references/matchers.md
516
+ - skills/rspec/references/mocks.md
517
+ - skills/rspec/references/rails.md
518
+ - templates/soul.md
519
+ - workflows/commit.md
520
+ - workflows/create_handoff.md
521
+ - workflows/create_note.md
522
+ - workflows/create_plan.md
523
+ - workflows/decompose_ticket.md
524
+ - workflows/feature.md
525
+ - workflows/implement_plan.md
526
+ - workflows/iterate_plan.md
527
+ - workflows/research_codebase.md
528
+ - workflows/resume_handoff.md
529
+ - workflows/review_pr.md
530
+ - workflows/thoughts_init.md
531
+ - workflows/validate_plan.md
245
532
  homepage: https://github.com/hoblin/anima
246
533
  licenses:
247
534
  - MIT
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Api
4
- # REST endpoint for session management. The TUI client uses this to
5
- # obtain a session ID before subscribing to the WebSocket channel.
6
- class SessionsController < ApplicationController
7
- # Returns the most recent session or creates one if none exist.
8
- #
9
- # GET /api/sessions/current
10
- # @return [JSON] { id: Integer }
11
- def current
12
- session = Session.last || Session.create!
13
- render json: {id: session.id}
14
- end
15
-
16
- # Creates a new conversation session.
17
- #
18
- # POST /api/sessions
19
- # @return [JSON] { id: Integer }
20
- def create
21
- session = Session.create!
22
- render json: {id: session.id}, status: :created
23
- end
24
- end
25
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Events
4
- module Subscribers
5
- # Forwards EventBus events to Action Cable, bridging internal pub/sub
6
- # to external WebSocket clients. Each event is broadcast to the
7
- # session-specific stream (e.g. "session_42"), matching the stream
8
- # name used by {SessionChannel}.
9
- #
10
- # Events are decorated via {EventDecorator} before broadcast, adding
11
- # structured data for the session's current view mode. The TUI
12
- # receives semantic hashes (role, content, timestamp) and never loads Draper.
13
- #
14
- # Only events with a valid session_id are broadcast — events without
15
- # one have no destination channel and are silently skipped.
16
- #
17
- # @example
18
- # Events::Bus.subscribe(Events::Subscribers::ActionCableBridge.instance)
19
- # # Now all events with session_id flow to "session_<id>" streams
20
- class ActionCableBridge
21
- include Events::Subscriber
22
- include Singleton
23
-
24
- # Receives a Rails.event notification hash, decorates the payload
25
- # with rendered output, and broadcasts to the session's Action Cable stream.
26
- # Loads the session to determine the current view_mode for decoration.
27
- #
28
- # @param event [Hash] with :payload containing event data including :session_id
29
- def emit(event)
30
- payload = event[:payload]
31
- return unless payload.is_a?(Hash)
32
-
33
- session_id = payload[:session_id]
34
- return if session_id.nil?
35
-
36
- mode = session_view_mode(session_id)
37
- ActionCable.server.broadcast("session_#{session_id}", decorate_payload(payload, mode))
38
- end
39
-
40
- private
41
-
42
- # Decorates the payload hash with structured data for the given view mode.
43
- # Uses string keys for the +rendered+ hash to match JSON wire format.
44
- # Falls back to the raw payload if decoration fails.
45
- def decorate_payload(payload, mode = "basic")
46
- decorator = EventDecorator.for(payload)
47
- return payload unless decorator
48
-
49
- payload.merge("rendered" => {mode => decorator.render(mode)})
50
- end
51
-
52
- # Looks up the session's current view_mode. Falls back to "basic"
53
- # if the session cannot be found (e.g. race condition during deletion).
54
- def session_view_mode(session_id)
55
- Session.where(id: session_id).pick(:view_mode) || "basic"
56
- end
57
- end
58
- end
59
- end