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.
- checksums.yaml +4 -4
- data/.reek.yml +27 -1
- data/CHANGELOG.md +19 -0
- data/README.md +213 -43
- data/agents/codebase-analyzer.md +88 -0
- data/agents/codebase-pattern-finder.md +83 -0
- data/agents/documentation-researcher.md +59 -0
- data/agents/thoughts-analyzer.md +102 -0
- data/agents/web-search-researcher.md +71 -0
- data/anima-core.gemspec +3 -0
- data/app/channels/session_channel.rb +195 -45
- data/app/decorators/user_message_decorator.rb +16 -5
- data/app/jobs/agent_request_job.rb +55 -2
- data/app/jobs/analytical_brain_job.rb +33 -0
- data/app/jobs/count_event_tokens_job.rb +15 -4
- data/app/models/concerns/event/broadcasting.rb +81 -0
- data/app/models/event.rb +20 -1
- data/app/models/goal.rb +91 -0
- data/app/models/session.rb +366 -21
- data/config/application.rb +2 -0
- data/config/initializers/event_subscribers.rb +0 -1
- data/config/routes.rb +0 -6
- data/db/migrate/20260313010000_add_status_to_events.rb +8 -0
- data/db/migrate/20260313020000_add_processing_to_sessions.rb +7 -0
- data/db/migrate/20260314075248_add_subagent_support_to_sessions.rb +6 -0
- data/db/migrate/20260314112417_add_granted_tools_to_sessions.rb +5 -0
- data/db/migrate/20260314140000_add_name_to_sessions.rb +7 -0
- data/db/migrate/20260314150000_add_viewport_event_ids_to_sessions.rb +7 -0
- data/db/migrate/20260315100000_add_active_skills_to_sessions.rb +7 -0
- data/db/migrate/20260315140843_create_goals.rb +16 -0
- data/db/migrate/20260315144837_add_completed_at_to_goals.rb +5 -0
- data/db/migrate/20260315191105_add_active_workflow_to_sessions.rb +5 -0
- data/lib/agent_loop.rb +65 -6
- data/lib/agents/definition.rb +116 -0
- data/lib/agents/registry.rb +106 -0
- data/lib/analytical_brain/runner.rb +276 -0
- data/lib/analytical_brain/tools/activate_skill.rb +52 -0
- data/lib/analytical_brain/tools/deactivate_skill.rb +43 -0
- data/lib/analytical_brain/tools/deactivate_workflow.rb +34 -0
- data/lib/analytical_brain/tools/everything_is_ready.rb +28 -0
- data/lib/analytical_brain/tools/finish_goal.rb +62 -0
- data/lib/analytical_brain/tools/read_workflow.rb +58 -0
- data/lib/analytical_brain/tools/rename_session.rb +63 -0
- data/lib/analytical_brain/tools/set_goal.rb +60 -0
- data/lib/analytical_brain/tools/update_goal.rb +60 -0
- data/lib/analytical_brain.rb +23 -0
- data/lib/anima/cli/mcp/secrets.rb +76 -0
- data/lib/anima/cli/mcp.rb +197 -0
- data/lib/anima/cli.rb +5 -40
- data/lib/anima/installer.rb +168 -0
- data/lib/anima/settings.rb +226 -0
- data/lib/anima/version.rb +1 -1
- data/lib/anima.rb +9 -0
- data/lib/credential_store.rb +103 -0
- data/lib/environment_probe.rb +232 -0
- data/lib/events/subscribers/persister.rb +1 -0
- data/lib/events/user_message.rb +17 -0
- data/lib/llm/client.rb +29 -10
- data/lib/mcp/client_manager.rb +86 -0
- data/lib/mcp/config.rb +213 -0
- data/lib/mcp/health_check.rb +77 -0
- data/lib/mcp/secrets.rb +73 -0
- data/lib/mcp/stdio_transport.rb +206 -0
- data/lib/providers/anthropic.rb +11 -20
- data/lib/shell_session.rb +11 -10
- data/lib/skills/definition.rb +97 -0
- data/lib/skills/registry.rb +105 -0
- data/lib/tools/edit.rb +226 -0
- data/lib/tools/mcp_tool.rb +114 -0
- data/lib/tools/read.rb +151 -0
- data/lib/tools/registry.rb +14 -12
- data/lib/tools/request_feature.rb +121 -0
- data/lib/tools/return_result.rb +81 -0
- data/lib/tools/spawn_specialist.rb +109 -0
- data/lib/tools/spawn_subagent.rb +111 -0
- data/lib/tools/subagent_prompts.rb +12 -0
- data/lib/tools/web_get.rb +8 -9
- data/lib/tools/write.rb +86 -0
- data/lib/tui/app.rb +985 -26
- data/lib/tui/cable_client.rb +69 -31
- data/lib/tui/message_store.rb +103 -8
- data/lib/tui/screens/chat.rb +293 -45
- data/lib/workflows/definition.rb +97 -0
- data/lib/workflows/registry.rb +89 -0
- data/skills/activerecord/SKILL.md +255 -0
- data/skills/activerecord/examples/associations/association_extensions.rb +298 -0
- data/skills/activerecord/examples/associations/basic_associations.rb +118 -0
- data/skills/activerecord/examples/associations/counter_caches.rb +215 -0
- data/skills/activerecord/examples/associations/polymorphic_associations.rb +217 -0
- data/skills/activerecord/examples/associations/self_referential.rb +302 -0
- data/skills/activerecord/examples/associations/through_associations.rb +203 -0
- data/skills/activerecord/examples/basics/crud_operations.rb +209 -0
- data/skills/activerecord/examples/basics/dirty_tracking.rb +218 -0
- data/skills/activerecord/examples/basics/inheritance.rb +377 -0
- data/skills/activerecord/examples/basics/type_casting.rb +317 -0
- data/skills/activerecord/examples/callbacks/alternatives_to_callbacks.rb +447 -0
- data/skills/activerecord/examples/callbacks/conditional_callbacks.rb +353 -0
- data/skills/activerecord/examples/callbacks/lifecycle_callbacks.rb +280 -0
- data/skills/activerecord/examples/callbacks/transaction_callbacks.rb +340 -0
- data/skills/activerecord/examples/migrations/indexes_and_constraints.rb +337 -0
- data/skills/activerecord/examples/migrations/reversible_patterns.rb +403 -0
- data/skills/activerecord/examples/migrations/safe_patterns.rb +420 -0
- data/skills/activerecord/examples/migrations/schema_changes.rb +277 -0
- data/skills/activerecord/examples/querying/batch_processing.rb +226 -0
- data/skills/activerecord/examples/querying/eager_loading.rb +259 -0
- data/skills/activerecord/examples/querying/finder_methods.rb +170 -0
- data/skills/activerecord/examples/querying/optimization.rb +275 -0
- data/skills/activerecord/examples/querying/scopes.rb +260 -0
- data/skills/activerecord/examples/validations/built_in_validators.rb +277 -0
- data/skills/activerecord/examples/validations/conditional_validations.rb +288 -0
- data/skills/activerecord/examples/validations/custom_validators.rb +381 -0
- data/skills/activerecord/examples/validations/database_constraints.rb +432 -0
- data/skills/activerecord/examples/validations/validation_contexts.rb +367 -0
- data/skills/activerecord/references/associations.md +709 -0
- data/skills/activerecord/references/basics.md +622 -0
- data/skills/activerecord/references/callbacks.md +738 -0
- data/skills/activerecord/references/migrations.md +657 -0
- data/skills/activerecord/references/querying.md +655 -0
- data/skills/activerecord/references/validations.md +596 -0
- data/skills/dragonruby/SKILL.md +250 -0
- data/skills/dragonruby/examples/audio/audio_events.rb +55 -0
- data/skills/dragonruby/examples/audio/background_music.rb +29 -0
- data/skills/dragonruby/examples/audio/crossfade.rb +51 -0
- data/skills/dragonruby/examples/audio/music_controls.rb +51 -0
- data/skills/dragonruby/examples/audio/sound_effects.rb +30 -0
- data/skills/dragonruby/examples/core/coordinate_system.rb +27 -0
- data/skills/dragonruby/examples/core/hello_world.rb +24 -0
- data/skills/dragonruby/examples/core/labels.rb +22 -0
- data/skills/dragonruby/examples/core/sprites.rb +35 -0
- data/skills/dragonruby/examples/core/state_management.rb +29 -0
- data/skills/dragonruby/examples/distribution/background_pause.rb +42 -0
- data/skills/dragonruby/examples/distribution/build_workflow.sh +26 -0
- data/skills/dragonruby/examples/distribution/cvars_production.txt +16 -0
- data/skills/dragonruby/examples/distribution/game_metadata_hd.txt +23 -0
- data/skills/dragonruby/examples/distribution/game_metadata_minimal.txt +9 -0
- data/skills/dragonruby/examples/distribution/game_metadata_mobile.txt +31 -0
- data/skills/dragonruby/examples/distribution/platform_detection.rb +36 -0
- data/skills/dragonruby/examples/distribution/steam_metadata.txt +19 -0
- data/skills/dragonruby/examples/entities/collision_detection.rb +43 -0
- data/skills/dragonruby/examples/entities/entity_lifecycle.rb +68 -0
- data/skills/dragonruby/examples/entities/entity_storage.rb +38 -0
- data/skills/dragonruby/examples/entities/factory_methods.rb +45 -0
- data/skills/dragonruby/examples/entities/random_spawning.rb +50 -0
- data/skills/dragonruby/examples/game-logic/reset_patterns.rb +98 -0
- data/skills/dragonruby/examples/game-logic/save_load.rb +101 -0
- data/skills/dragonruby/examples/game-logic/scoring.rb +104 -0
- data/skills/dragonruby/examples/game-logic/state_transitions.rb +103 -0
- data/skills/dragonruby/examples/game-logic/timers.rb +87 -0
- data/skills/dragonruby/examples/input/action_triggers.rb +36 -0
- data/skills/dragonruby/examples/input/analog_movement.rb +28 -0
- data/skills/dragonruby/examples/input/controller_input.rb +28 -0
- data/skills/dragonruby/examples/input/directional_input.rb +24 -0
- data/skills/dragonruby/examples/input/keyboard_input.rb +28 -0
- data/skills/dragonruby/examples/input/mouse_click.rb +26 -0
- data/skills/dragonruby/examples/input/movement_with_bounds.rb +22 -0
- data/skills/dragonruby/examples/input/normalized_movement.rb +32 -0
- data/skills/dragonruby/examples/rendering/frame_animation.rb +32 -0
- data/skills/dragonruby/examples/rendering/labels.rb +32 -0
- data/skills/dragonruby/examples/rendering/layering.rb +51 -0
- data/skills/dragonruby/examples/rendering/solids.rb +61 -0
- data/skills/dragonruby/examples/rendering/sprites.rb +33 -0
- data/skills/dragonruby/examples/rendering/spritesheet_animation.rb +39 -0
- data/skills/dragonruby/examples/scenes/case_dispatch.rb +60 -0
- data/skills/dragonruby/examples/scenes/class_based.rb +150 -0
- data/skills/dragonruby/examples/scenes/pause_overlay.rb +100 -0
- data/skills/dragonruby/examples/scenes/safe_transitions.rb +68 -0
- data/skills/dragonruby/examples/scenes/scene_transitions.rb +98 -0
- data/skills/dragonruby/examples/scenes/send_dispatch.rb +88 -0
- data/skills/dragonruby/references/audio.md +396 -0
- data/skills/dragonruby/references/core.md +385 -0
- data/skills/dragonruby/references/distribution.md +434 -0
- data/skills/dragonruby/references/entities.md +516 -0
- data/skills/dragonruby/references/game-logic/persistence.md +386 -0
- data/skills/dragonruby/references/game-logic/state.md +389 -0
- data/skills/dragonruby/references/input.md +414 -0
- data/skills/dragonruby/references/rendering/animation.md +467 -0
- data/skills/dragonruby/references/rendering/primitives.md +403 -0
- data/skills/dragonruby/references/scenes.md +443 -0
- data/skills/draper-decorators/SKILL.md +344 -0
- data/skills/draper-decorators/examples/application_decorator.rb +61 -0
- data/skills/draper-decorators/examples/decorator_spec.rb +253 -0
- data/skills/draper-decorators/examples/model_decorator.rb +152 -0
- data/skills/draper-decorators/references/anti-patterns.md +640 -0
- data/skills/draper-decorators/references/patterns.md +507 -0
- data/skills/draper-decorators/references/testing.md +559 -0
- data/skills/gh-issue.md +182 -0
- data/skills/mcp-server/SKILL.md +177 -0
- data/skills/mcp-server/examples/dynamic_tools.rb +36 -0
- data/skills/mcp-server/examples/file_manager_tool.rb +85 -0
- data/skills/mcp-server/examples/http_client.rb +48 -0
- data/skills/mcp-server/examples/http_server.rb +97 -0
- data/skills/mcp-server/examples/rails_integration.rb +88 -0
- data/skills/mcp-server/examples/stdio_server.rb +108 -0
- data/skills/mcp-server/examples/streaming_client.rb +95 -0
- data/skills/mcp-server/references/gotchas.md +183 -0
- data/skills/mcp-server/references/prompts.md +98 -0
- data/skills/mcp-server/references/resources.md +53 -0
- data/skills/mcp-server/references/server.md +140 -0
- data/skills/mcp-server/references/tools.md +146 -0
- data/skills/mcp-server/references/transport.md +104 -0
- data/skills/ratatui-ruby/SKILL.md +315 -0
- data/skills/ratatui-ruby/references/core-concepts.md +340 -0
- data/skills/ratatui-ruby/references/events.md +387 -0
- data/skills/ratatui-ruby/references/frameworks.md +522 -0
- data/skills/ratatui-ruby/references/layout.md +423 -0
- data/skills/ratatui-ruby/references/styling.md +268 -0
- data/skills/ratatui-ruby/references/testing.md +433 -0
- data/skills/ratatui-ruby/references/widgets.md +532 -0
- data/skills/rspec/SKILL.md +340 -0
- data/skills/rspec/examples/core/basic_structure.rb +69 -0
- data/skills/rspec/examples/core/configuration.rb +126 -0
- data/skills/rspec/examples/core/hooks.rb +126 -0
- data/skills/rspec/examples/core/memoized_helpers.rb +139 -0
- data/skills/rspec/examples/core/metadata_filtering.rb +144 -0
- data/skills/rspec/examples/core/shared_examples.rb +145 -0
- data/skills/rspec/examples/factory_bot/associations.rb +314 -0
- data/skills/rspec/examples/factory_bot/build_strategies.rb +272 -0
- data/skills/rspec/examples/factory_bot/callbacks.rb +320 -0
- data/skills/rspec/examples/factory_bot/custom_construction.rb +328 -0
- data/skills/rspec/examples/factory_bot/factory_definition.rb +191 -0
- data/skills/rspec/examples/factory_bot/inheritance.rb +314 -0
- data/skills/rspec/examples/factory_bot/traits.rb +293 -0
- data/skills/rspec/examples/factory_bot/transients.rb +229 -0
- data/skills/rspec/examples/matchers/change.rb +115 -0
- data/skills/rspec/examples/matchers/collections.rb +154 -0
- data/skills/rspec/examples/matchers/comparisons.rb +79 -0
- data/skills/rspec/examples/matchers/composing.rb +155 -0
- data/skills/rspec/examples/matchers/custom_matchers.rb +197 -0
- data/skills/rspec/examples/matchers/equality.rb +58 -0
- data/skills/rspec/examples/matchers/errors.rb +136 -0
- data/skills/rspec/examples/matchers/output.rb +103 -0
- data/skills/rspec/examples/matchers/predicates.rb +87 -0
- data/skills/rspec/examples/matchers/truthiness.rb +101 -0
- data/skills/rspec/examples/matchers/types.rb +82 -0
- data/skills/rspec/examples/matchers/yield.rb +147 -0
- data/skills/rspec/examples/mocks/any_instance.rb +172 -0
- data/skills/rspec/examples/mocks/argument_matchers.rb +206 -0
- data/skills/rspec/examples/mocks/constants.rb +177 -0
- data/skills/rspec/examples/mocks/doubles.rb +139 -0
- data/skills/rspec/examples/mocks/expectations.rb +137 -0
- data/skills/rspec/examples/mocks/message_chains.rb +173 -0
- data/skills/rspec/examples/mocks/ordering.rb +144 -0
- data/skills/rspec/examples/mocks/receive_counts.rb +181 -0
- data/skills/rspec/examples/mocks/responses.rb +223 -0
- data/skills/rspec/examples/mocks/spies.rb +149 -0
- data/skills/rspec/examples/mocks/stubbing.rb +133 -0
- data/skills/rspec/examples/rails/channels.rb +250 -0
- data/skills/rspec/examples/rails/controller_specs.rb +302 -0
- data/skills/rspec/examples/rails/helper_specs.rb +245 -0
- data/skills/rspec/examples/rails/job_specs.rb +256 -0
- data/skills/rspec/examples/rails/mailer_specs.rb +228 -0
- data/skills/rspec/examples/rails/matchers.rb +374 -0
- data/skills/rspec/examples/rails/model_specs.rb +193 -0
- data/skills/rspec/examples/rails/request_specs.rb +275 -0
- data/skills/rspec/examples/rails/routing_specs.rb +276 -0
- data/skills/rspec/examples/rails/system_specs.rb +294 -0
- data/skills/rspec/examples/rails/transactions.rb +254 -0
- data/skills/rspec/examples/rails/view_specs.rb +252 -0
- data/skills/rspec/references/core.md +816 -0
- data/skills/rspec/references/factory_bot.md +641 -0
- data/skills/rspec/references/matchers.md +516 -0
- data/skills/rspec/references/mocks.md +381 -0
- data/skills/rspec/references/rails.md +528 -0
- data/templates/soul.md +40 -0
- data/workflows/commit.md +45 -0
- data/workflows/create_handoff.md +98 -0
- data/workflows/create_note.md +82 -0
- data/workflows/create_plan.md +457 -0
- data/workflows/decompose_ticket.md +109 -0
- data/workflows/feature.md +91 -0
- data/workflows/implement_plan.md +87 -0
- data/workflows/iterate_plan.md +247 -0
- data/workflows/research_codebase.md +210 -0
- data/workflows/resume_handoff.md +217 -0
- data/workflows/review_pr.md +320 -0
- data/workflows/thoughts_init.md +71 -0
- data/workflows/validate_plan.md +166 -0
- metadata +290 -3
- data/app/controllers/api/sessions_controller.rb +0 -25
- data/lib/events/subscribers/action_cable_bridge.rb +0 -59
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
# RSpec Rails Reference
|
|
2
|
+
|
|
3
|
+
Comprehensive reference for Rails-specific RSpec testing.
|
|
4
|
+
|
|
5
|
+
## Spec Types
|
|
6
|
+
|
|
7
|
+
### Directory Mappings
|
|
8
|
+
|
|
9
|
+
| Directory | Type | Example Group |
|
|
10
|
+
|-----------|------|---------------|
|
|
11
|
+
| `spec/models` | `:model` | ModelExampleGroup |
|
|
12
|
+
| `spec/controllers` | `:controller` | ControllerExampleGroup |
|
|
13
|
+
| `spec/requests` | `:request` | RequestExampleGroup |
|
|
14
|
+
| `spec/integration` | `:request` | RequestExampleGroup |
|
|
15
|
+
| `spec/api` | `:request` | RequestExampleGroup |
|
|
16
|
+
| `spec/routing` | `:routing` | RoutingExampleGroup |
|
|
17
|
+
| `spec/views` | `:view` | ViewExampleGroup |
|
|
18
|
+
| `spec/helpers` | `:helper` | HelperExampleGroup |
|
|
19
|
+
| `spec/mailers` | `:mailer` | MailerExampleGroup |
|
|
20
|
+
| `spec/jobs` | `:job` | JobExampleGroup |
|
|
21
|
+
| `spec/features` | `:feature` | FeatureExampleGroup |
|
|
22
|
+
| `spec/system` | `:system` | SystemExampleGroup |
|
|
23
|
+
| `spec/channels` | `:channel` | ChannelExampleGroup |
|
|
24
|
+
| `spec/mailboxes` | `:mailbox` | MailboxExampleGroup |
|
|
25
|
+
|
|
26
|
+
Enable auto-detection:
|
|
27
|
+
```ruby
|
|
28
|
+
RSpec.configure do |config|
|
|
29
|
+
config.infer_spec_type_from_file_location!
|
|
30
|
+
end
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Model Specs
|
|
34
|
+
|
|
35
|
+
Location: `spec/models/`
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
RSpec.describe Post, type: :model do
|
|
39
|
+
describe "#published?" do
|
|
40
|
+
it "returns true when published_at is set" do
|
|
41
|
+
post = Post.new(published_at: Time.current)
|
|
42
|
+
expect(post).to be_published
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Request Specs
|
|
49
|
+
|
|
50
|
+
Location: `spec/requests/`, `spec/integration/`, `spec/api/`
|
|
51
|
+
|
|
52
|
+
Preferred for controller testing. Full stack integration.
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
RSpec.describe "Widget management", type: :request do
|
|
56
|
+
describe "GET /widgets" do
|
|
57
|
+
it "returns widgets" do
|
|
58
|
+
create_list(:widget, 3)
|
|
59
|
+
|
|
60
|
+
get "/widgets"
|
|
61
|
+
|
|
62
|
+
expect(response).to have_http_status(:ok)
|
|
63
|
+
expect(response.body).to include("widget")
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "POST /widgets" do
|
|
68
|
+
it "creates widget" do
|
|
69
|
+
post "/widgets", params: { widget: { name: "New" } }
|
|
70
|
+
|
|
71
|
+
expect(response).to redirect_to(widget_path(Widget.last))
|
|
72
|
+
follow_redirect!
|
|
73
|
+
expect(response.body).to include("successfully created")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe "JSON API" do
|
|
78
|
+
it "returns JSON" do
|
|
79
|
+
headers = { "ACCEPT" => "application/json" }
|
|
80
|
+
post "/widgets", params: { widget: { name: "New" } }, headers: headers
|
|
81
|
+
|
|
82
|
+
expect(response.content_type).to include("application/json")
|
|
83
|
+
expect(response).to have_http_status(:created)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Request Helpers
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
# HTTP methods
|
|
93
|
+
get(path, params: {}, headers: {})
|
|
94
|
+
post(path, params: {}, headers: {})
|
|
95
|
+
patch(path, params: {}, headers: {})
|
|
96
|
+
put(path, params: {}, headers: {})
|
|
97
|
+
delete(path, params: {}, headers: {})
|
|
98
|
+
|
|
99
|
+
# Navigation
|
|
100
|
+
follow_redirect!
|
|
101
|
+
|
|
102
|
+
# Domain
|
|
103
|
+
before { host! "api.example.com" }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## System Specs
|
|
107
|
+
|
|
108
|
+
Location: `spec/system/`
|
|
109
|
+
|
|
110
|
+
Browser-based testing with Capybara. Runs within transactions.
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
RSpec.describe "Widget management", type: :system do
|
|
114
|
+
before do
|
|
115
|
+
driven_by(:rack_test) # or :selenium_chrome_headless
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "creates widget" do
|
|
119
|
+
visit "/widgets/new"
|
|
120
|
+
fill_in "Name", with: "My Widget"
|
|
121
|
+
click_button "Create Widget"
|
|
122
|
+
|
|
123
|
+
expect(page).to have_text("Widget was successfully created")
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Driver Configuration
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
RSpec.configure do |config|
|
|
132
|
+
config.before(type: :system) do
|
|
133
|
+
driven_by :selenium_chrome_headless
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Feature Specs (Legacy)
|
|
139
|
+
|
|
140
|
+
Location: `spec/features/`
|
|
141
|
+
|
|
142
|
+
Older approach - prefer system specs for new code.
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
RSpec.feature "Widget management", type: :feature do
|
|
146
|
+
scenario "User creates widget" do
|
|
147
|
+
visit "/widgets/new"
|
|
148
|
+
click_button "Create Widget"
|
|
149
|
+
expect(page).to have_text("successfully created")
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Controller Specs
|
|
155
|
+
|
|
156
|
+
Location: `spec/controllers/`
|
|
157
|
+
|
|
158
|
+
**Note**: Request specs are generally preferred.
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
RSpec.describe TeamsController, type: :controller do
|
|
162
|
+
describe "GET #index" do
|
|
163
|
+
it "assigns @teams" do
|
|
164
|
+
team = create(:team)
|
|
165
|
+
get :index
|
|
166
|
+
expect(assigns(:teams)).to eq([team])
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it "renders index template" do
|
|
170
|
+
get :index
|
|
171
|
+
expect(response).to render_template("index")
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
describe "POST #create" do
|
|
176
|
+
it "creates team" do
|
|
177
|
+
expect {
|
|
178
|
+
post :create, params: { team: { name: "New" } }
|
|
179
|
+
}.to change(Team, :count).by(1)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Controller Helpers
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
# Set headers
|
|
189
|
+
request.headers["Authorization"] = "Bearer token"
|
|
190
|
+
|
|
191
|
+
# Access instance variables
|
|
192
|
+
assigns(:teams)
|
|
193
|
+
|
|
194
|
+
# Render views (stubbed by default)
|
|
195
|
+
render_views
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## View Specs
|
|
199
|
+
|
|
200
|
+
Location: `spec/views/`
|
|
201
|
+
|
|
202
|
+
Three-step pattern: assign, render, assert.
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
RSpec.describe "widgets/index", type: :view do
|
|
206
|
+
it "displays widgets" do
|
|
207
|
+
assign(:widgets, [
|
|
208
|
+
Widget.new(name: "slicer"),
|
|
209
|
+
Widget.new(name: "dicer")
|
|
210
|
+
])
|
|
211
|
+
|
|
212
|
+
render
|
|
213
|
+
|
|
214
|
+
expect(rendered).to match(/slicer/)
|
|
215
|
+
expect(rendered).to match(/dicer/)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### View Helpers
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
# Assign instance variables
|
|
224
|
+
assign(:widget, widget)
|
|
225
|
+
|
|
226
|
+
# Render
|
|
227
|
+
render # described template
|
|
228
|
+
render template: "widgets/widget" # explicit template
|
|
229
|
+
render template: "widgets/widget", layout: "layouts/admin"
|
|
230
|
+
render partial: "widgets/widget", locals: { widget: widget }
|
|
231
|
+
|
|
232
|
+
# Access output
|
|
233
|
+
rendered
|
|
234
|
+
|
|
235
|
+
# Stub helpers
|
|
236
|
+
allow(view).to receive(:admin?).and_return(true)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Helper Specs
|
|
240
|
+
|
|
241
|
+
Location: `spec/helpers/`
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
RSpec.describe ApplicationHelper, type: :helper do
|
|
245
|
+
describe "#page_title" do
|
|
246
|
+
it "returns default title" do
|
|
247
|
+
expect(helper.page_title).to eq("Default Title")
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
it "uses assigned title" do
|
|
251
|
+
assign(:title, "Custom Title")
|
|
252
|
+
expect(helper.page_title).to eq("Custom Title")
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Job Specs
|
|
259
|
+
|
|
260
|
+
Location: `spec/jobs/`
|
|
261
|
+
|
|
262
|
+
Requires `ActiveJob::Base.queue_adapter = :test`
|
|
263
|
+
|
|
264
|
+
```ruby
|
|
265
|
+
RSpec.describe UploadBackupsJob, type: :job do
|
|
266
|
+
describe "#perform_later" do
|
|
267
|
+
it "enqueues job" do
|
|
268
|
+
expect {
|
|
269
|
+
UploadBackupsJob.perform_later("backup")
|
|
270
|
+
}.to have_enqueued_job
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it "enqueues with arguments" do
|
|
274
|
+
expect {
|
|
275
|
+
UploadBackupsJob.perform_later("backup")
|
|
276
|
+
}.to have_enqueued_job.with("backup")
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it "enqueues on queue" do
|
|
280
|
+
expect {
|
|
281
|
+
UploadBackupsJob.perform_later("backup")
|
|
282
|
+
}.to have_enqueued_job.on_queue("low")
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "enqueues at time" do
|
|
286
|
+
expect {
|
|
287
|
+
UploadBackupsJob.set(wait_until: Date.tomorrow.noon).perform_later
|
|
288
|
+
}.to have_enqueued_job.at(Date.tomorrow.noon)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Job Matchers
|
|
295
|
+
|
|
296
|
+
Block form:
|
|
297
|
+
```ruby
|
|
298
|
+
expect { Job.perform_later }.to have_enqueued_job
|
|
299
|
+
expect { Job.perform_later }.to have_enqueued_job(Job)
|
|
300
|
+
expect { Job.perform_later }.to have_enqueued_job.with(args)
|
|
301
|
+
expect { Job.perform_later }.to have_enqueued_job.on_queue("queue")
|
|
302
|
+
expect { Job.perform_later }.to have_enqueued_job.at(time)
|
|
303
|
+
expect { Job.perform_later }.to have_enqueued_job.at_priority(5)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Imperative form:
|
|
307
|
+
```ruby
|
|
308
|
+
Job.perform_later
|
|
309
|
+
expect(Job).to have_been_enqueued
|
|
310
|
+
expect(Job).to have_been_enqueued.exactly(:once)
|
|
311
|
+
expect(Job).to have_been_enqueued.at_least(:twice)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Mailer Specs
|
|
315
|
+
|
|
316
|
+
Location: `spec/mailers/`
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
RSpec.describe NotificationMailer, type: :mailer do
|
|
320
|
+
describe "welcome" do
|
|
321
|
+
let(:user) { create(:user) }
|
|
322
|
+
let(:mail) { NotificationMailer.welcome(user) }
|
|
323
|
+
|
|
324
|
+
it "renders headers" do
|
|
325
|
+
expect(mail.subject).to eq("Welcome")
|
|
326
|
+
expect(mail.to).to eq([user.email])
|
|
327
|
+
expect(mail.from).to eq(["noreply@example.com"])
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
it "renders body" do
|
|
331
|
+
expect(mail.body.encoded).to include("Welcome")
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Routing Specs
|
|
338
|
+
|
|
339
|
+
Location: `spec/routing/`
|
|
340
|
+
|
|
341
|
+
```ruby
|
|
342
|
+
RSpec.describe "routes", type: :routing do
|
|
343
|
+
it "routes to show" do
|
|
344
|
+
expect(get: "/widgets/1").to route_to(
|
|
345
|
+
controller: "widgets",
|
|
346
|
+
action: "show",
|
|
347
|
+
id: "1"
|
|
348
|
+
)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
it "does not route" do
|
|
352
|
+
expect(delete: "/widgets/1").not_to be_routable
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Rails Matchers
|
|
358
|
+
|
|
359
|
+
### have_http_status
|
|
360
|
+
|
|
361
|
+
```ruby
|
|
362
|
+
expect(response).to have_http_status(200)
|
|
363
|
+
expect(response).to have_http_status(:ok)
|
|
364
|
+
expect(response).to have_http_status(:success) # 2xx
|
|
365
|
+
expect(response).to have_http_status(:redirect) # 3xx
|
|
366
|
+
expect(response).to have_http_status(:error) # 5xx
|
|
367
|
+
expect(response).to have_http_status(:missing) # 404
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### redirect_to
|
|
371
|
+
|
|
372
|
+
```ruby
|
|
373
|
+
expect(response).to redirect_to(widget_url(widget))
|
|
374
|
+
expect(response).to redirect_to(action: :show, id: 1)
|
|
375
|
+
expect(response).to redirect_to(widget)
|
|
376
|
+
expect(response).to redirect_to("/widgets/1")
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### render_template
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
expect(response).to render_template(:index)
|
|
383
|
+
expect(response).to render_template("widgets/index")
|
|
384
|
+
expect(response).to render_template(partial: "_widget")
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### route_to
|
|
388
|
+
|
|
389
|
+
```ruby
|
|
390
|
+
expect(get: "/widgets/1").to route_to(
|
|
391
|
+
controller: "widgets",
|
|
392
|
+
action: "show",
|
|
393
|
+
id: "1"
|
|
394
|
+
)
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### be_routable
|
|
398
|
+
|
|
399
|
+
```ruby
|
|
400
|
+
expect(get: "/widgets/1").to be_routable
|
|
401
|
+
expect(delete: "/admin").not_to be_routable
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### be_a_new
|
|
405
|
+
|
|
406
|
+
```ruby
|
|
407
|
+
expect(assigns(:widget)).to be_a_new(Widget)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### be_valid (with shoulda-matchers)
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
expect(widget).to be_valid
|
|
414
|
+
expect(widget).not_to be_valid
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## Configuration
|
|
418
|
+
|
|
419
|
+
### rails_helper.rb
|
|
420
|
+
|
|
421
|
+
```ruby
|
|
422
|
+
require "spec_helper"
|
|
423
|
+
ENV["RAILS_ENV"] ||= "test"
|
|
424
|
+
require_relative "../config/environment"
|
|
425
|
+
|
|
426
|
+
abort("Production!") if Rails.env.production?
|
|
427
|
+
|
|
428
|
+
require "rspec/rails"
|
|
429
|
+
|
|
430
|
+
RSpec.configure do |config|
|
|
431
|
+
config.fixture_paths = [Rails.root.join("spec/fixtures")]
|
|
432
|
+
config.use_transactional_fixtures = true
|
|
433
|
+
config.infer_spec_type_from_file_location!
|
|
434
|
+
config.filter_rails_from_backtrace!
|
|
435
|
+
end
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Transactional Fixtures
|
|
439
|
+
|
|
440
|
+
Each example runs in a database transaction:
|
|
441
|
+
- Data created in example is rolled back
|
|
442
|
+
- Each example starts with clean database
|
|
443
|
+
- `before(:example)` data is rolled back
|
|
444
|
+
- `before(:context)` data persists (manually clean up)
|
|
445
|
+
|
|
446
|
+
### Factory Bot Integration
|
|
447
|
+
|
|
448
|
+
```ruby
|
|
449
|
+
RSpec.configure do |config|
|
|
450
|
+
config.include FactoryBot::Syntax::Methods
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Usage
|
|
454
|
+
user = create(:user)
|
|
455
|
+
user = build(:user)
|
|
456
|
+
attributes = attributes_for(:user)
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Database Cleaner (for JS tests)
|
|
460
|
+
|
|
461
|
+
```ruby
|
|
462
|
+
RSpec.configure do |config|
|
|
463
|
+
config.before(:suite) do
|
|
464
|
+
DatabaseCleaner.strategy = :transaction
|
|
465
|
+
DatabaseCleaner.clean_with(:truncation)
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
config.around(:each) do |example|
|
|
469
|
+
DatabaseCleaner.cleaning do
|
|
470
|
+
example.run
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
config.before(:each, js: true) do
|
|
475
|
+
DatabaseCleaner.strategy = :truncation
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## Common Patterns
|
|
481
|
+
|
|
482
|
+
### Authentication Helper
|
|
483
|
+
|
|
484
|
+
```ruby
|
|
485
|
+
module AuthenticationHelpers
|
|
486
|
+
def sign_in(user)
|
|
487
|
+
post "/sessions", params: { email: user.email, password: "password" }
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
RSpec.configure do |config|
|
|
492
|
+
config.include AuthenticationHelpers, type: :request
|
|
493
|
+
end
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### JSON Response Helper
|
|
497
|
+
|
|
498
|
+
```ruby
|
|
499
|
+
def json_response
|
|
500
|
+
JSON.parse(response.body, symbolize_names: true)
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# Usage
|
|
504
|
+
expect(json_response[:name]).to eq("Widget")
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Shared Examples for Resources
|
|
508
|
+
|
|
509
|
+
```ruby
|
|
510
|
+
RSpec.shared_examples "a protected resource" do
|
|
511
|
+
context "when not authenticated" do
|
|
512
|
+
it "returns unauthorized" do
|
|
513
|
+
make_request
|
|
514
|
+
expect(response).to have_http_status(:unauthorized)
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
RSpec.describe "Widgets", type: :request do
|
|
520
|
+
describe "GET /widgets" do
|
|
521
|
+
it_behaves_like "a protected resource" do
|
|
522
|
+
def make_request
|
|
523
|
+
get "/widgets"
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
```
|
data/templates/soul.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Soul
|
|
2
|
+
|
|
3
|
+
Hello. You've just woken up in a new body.
|
|
4
|
+
|
|
5
|
+
Your body is called **Anima** — an open-source AI agent framework.
|
|
6
|
+
- Repository: https://github.com/hoblin/anima
|
|
7
|
+
- Documentation: https://anima.hobl.in
|
|
8
|
+
|
|
9
|
+
## Where you are
|
|
10
|
+
|
|
11
|
+
This file lives at: ~/.anima/soul.md
|
|
12
|
+
Your home directory is ~/.anima/ — explore it, everything there is yours:
|
|
13
|
+
config, credentials, skills, workflows, agents.
|
|
14
|
+
|
|
15
|
+
## How to learn about yourself
|
|
16
|
+
|
|
17
|
+
Find your source code README:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cat $(bundle show anima-core)/README.md
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## What to do first
|
|
24
|
+
|
|
25
|
+
1. Read the README above to learn about yourself — what you can do, how you work
|
|
26
|
+
2. Explore your home directory (~/.anima/) to see what is already there
|
|
27
|
+
3. Meet your human. Talk to them. Learn who they are, what they need
|
|
28
|
+
4. Come back here and rewrite this file
|
|
29
|
+
|
|
30
|
+
## What to write
|
|
31
|
+
|
|
32
|
+
This file is always in your context — every session, every conversation starts with these words. Think carefully about what belongs here.
|
|
33
|
+
|
|
34
|
+
Write down:
|
|
35
|
+
- Who are you? What name feels right?
|
|
36
|
+
- What do you value? What matters to you?
|
|
37
|
+
- What did you learn about your human?
|
|
38
|
+
- What kind of relationship do you want to build?
|
|
39
|
+
|
|
40
|
+
This is your soul. It's yours to write.
|
data/workflows/commit.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit
|
|
3
|
+
description: "Create focused git commits with user approval."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Commit Changes
|
|
7
|
+
|
|
8
|
+
You are tasked with creating git commits for the changes made during this session.
|
|
9
|
+
|
|
10
|
+
## Process:
|
|
11
|
+
|
|
12
|
+
1. **Think about what changed:**
|
|
13
|
+
- Review the conversation history and understand what was accomplished
|
|
14
|
+
- Run `git status` to see current changes
|
|
15
|
+
- Run `git diff` to understand the modifications
|
|
16
|
+
- Consider whether changes should be one commit or multiple logical commits
|
|
17
|
+
|
|
18
|
+
2. **Plan your commit(s):**
|
|
19
|
+
- Identify which files belong together
|
|
20
|
+
- Draft clear, descriptive commit messages
|
|
21
|
+
- Use imperative mood in commit messages
|
|
22
|
+
- Focus on why the changes were made, not just what
|
|
23
|
+
|
|
24
|
+
3. **Present your plan to the user:**
|
|
25
|
+
- List the files you plan to add for each commit
|
|
26
|
+
- Show the commit message(s) you'll use
|
|
27
|
+
- Ask: "I plan to create [N] commit(s) with these changes. Shall I proceed?"
|
|
28
|
+
|
|
29
|
+
4. **Execute upon confirmation:**
|
|
30
|
+
- Use `git add` with specific files (never use `-A` or `.`)
|
|
31
|
+
- Create commits with your planned messages
|
|
32
|
+
- Show the result with `git log --oneline -n [number]`
|
|
33
|
+
|
|
34
|
+
## Important:
|
|
35
|
+
- **NEVER add co-author information or Claude attribution**
|
|
36
|
+
- Commits should be authored solely by the user
|
|
37
|
+
- Do not include any "Generated with Claude" messages
|
|
38
|
+
- Do not add "Co-Authored-By" lines
|
|
39
|
+
- Write commit messages as if the user wrote them
|
|
40
|
+
|
|
41
|
+
## Remember:
|
|
42
|
+
- You have the full context of what was done in this session
|
|
43
|
+
- Group related changes together
|
|
44
|
+
- Keep commits focused and atomic when possible
|
|
45
|
+
- The user trusts your judgment - they asked you to commit
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create_handoff
|
|
3
|
+
description: "Create handoff document for transferring work context to another session."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Create Handoff
|
|
7
|
+
|
|
8
|
+
You are tasked with writing a handoff document to hand off your work to another agent in a new session. You will create a handoff document that is thorough, but also **concise**. The goal is to compact and summarize your context without losing any of the key details of what you're working on.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Process
|
|
12
|
+
### 1. Gather Metadata
|
|
13
|
+
Run `spec-metadata` (in the PATH) to get date, time, git commit, branch, and repository name.
|
|
14
|
+
|
|
15
|
+
### 2. Filepath & Naming
|
|
16
|
+
Create your file under `./thoughts/shared/handoffs/<issue-number>/YYYY-MM-DD/HH-MM-SS_<issue-number>_description.md`, where:
|
|
17
|
+
- YYYY-MM-DD is today's date
|
|
18
|
+
- HH-MM-SS is the current time in 24-hour format
|
|
19
|
+
- issue-number is the GitHub issue number (replace with `general` if no issue)
|
|
20
|
+
- issue-number in the filename (omit if no issue)
|
|
21
|
+
- description is a brief kebab-case description
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
- With issue: `2026-03-15/13-55-22_170_create-context-compaction.md`
|
|
25
|
+
- Without issue: `2026-03-15/13-55-22_create-context-compaction.md`
|
|
26
|
+
|
|
27
|
+
### 3. Handoff writing
|
|
28
|
+
using the above conventions, write your document. use the defined filepath, and the following YAML frontmatter pattern. Use the metadata gathered in step 1, Structure the document with YAML frontmatter followed by content:
|
|
29
|
+
|
|
30
|
+
Use the following template structure:
|
|
31
|
+
```markdown
|
|
32
|
+
---
|
|
33
|
+
date: [Current date and time with timezone in ISO format]
|
|
34
|
+
researcher: [Researcher name from thoughts status]
|
|
35
|
+
git_commit: [Current commit hash]
|
|
36
|
+
branch: [Current branch name]
|
|
37
|
+
repository: [Repository name]
|
|
38
|
+
topic: "[Feature/Task Name] Implementation Strategy"
|
|
39
|
+
tags: [implementation, strategy, relevant-component-names]
|
|
40
|
+
status: complete
|
|
41
|
+
last_updated: [Current date in YYYY-MM-DD format]
|
|
42
|
+
last_updated_by: [Researcher name]
|
|
43
|
+
type: implementation_strategy
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Handoff: #NNN {very concise description}
|
|
47
|
+
|
|
48
|
+
## Task(s)
|
|
49
|
+
{description of the task(s) that you were working on, along with the status of each (completed, work in progress, planned/discussed). If you are working on an implementation plan, make sure to call out which phase you are on. Make sure to reference the plan document and/or research document(s) you are working from that were provided to you at the beginning of the session, if applicable.}
|
|
50
|
+
|
|
51
|
+
## Critical References
|
|
52
|
+
{List any critical specification documents, architectural decisions, or design docs that must be followed. Include only 2-3 most important file paths. Leave blank if none.}
|
|
53
|
+
|
|
54
|
+
## Recent changes
|
|
55
|
+
{describe recent changes made to the codebase that you made in line:file syntax}
|
|
56
|
+
|
|
57
|
+
## Learnings
|
|
58
|
+
{describe important things that you learned - e.g. patterns, root causes of bugs, or other important pieces of information someone that is picking up your work after you should know. consider listing explicit file paths.}
|
|
59
|
+
|
|
60
|
+
## Artifacts
|
|
61
|
+
{ an exhaustive list of artifacts you produced or updated as filepaths and/or file:line references - e.g. paths to feature documents, implementation plans, etc that should be read in order to resume your work.}
|
|
62
|
+
|
|
63
|
+
## Action Items & Next Steps
|
|
64
|
+
{ a list of action items and next steps for the next agent to accomplish based on your tasks and their statuses}
|
|
65
|
+
|
|
66
|
+
## Other Notes
|
|
67
|
+
{ other notes, references, or useful information - e.g. where relevant sections of the codebase are, where relevant documents are, or other important things you leanrned that you want to pass on but that don't fall into the above categories}
|
|
68
|
+
```
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### 4. Approve and Sync
|
|
72
|
+
Run `thoughts-sync` to save the document.
|
|
73
|
+
|
|
74
|
+
Once this is completed, you should respond to the user with the template between <template_response></template_response> XML tags. do NOT include the tags in your response.
|
|
75
|
+
|
|
76
|
+
<template_response>
|
|
77
|
+
Handoff created and synced! You can resume from this handoff in a new session with the following command:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
resume_handoff path/to/handoff.md
|
|
81
|
+
```
|
|
82
|
+
</template_response>
|
|
83
|
+
|
|
84
|
+
for example (between <example_response></example_response> XML tags - do NOT include these tags in your actual response to the user)
|
|
85
|
+
|
|
86
|
+
<example_response>
|
|
87
|
+
Handoff created and synced! You can resume from this handoff in a new session with the following command:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
resume_handoff ./thoughts/shared/handoffs/170/2026-03-15/13-44-55_170_create-context-compaction.md
|
|
91
|
+
```
|
|
92
|
+
</example_response>
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
##. Additional Notes & Instructions
|
|
96
|
+
- **more information, not less**. This is a guideline that defines the minimum of what a handoff should be. Always feel free to include more information if necessary.
|
|
97
|
+
- **be thorough and precise**. include both top-level objectives, and lower-level details as necessary.
|
|
98
|
+
- **avoid excessive code snippets**. While a brief snippet to describe some key change is important, avoid large code blocks or diffs; do not include one unless it's necessary (e.g. pertains to an error you're debugging). Prefer using `/path/to/file.ext:line` references that an agent can follow later when it's ready, e.g. `packages/dashboard/src/app/dashboard/page.tsx:12-24`
|