roast-ai 0.1.6 → 0.2.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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +1 -1
  3. data/CHANGELOG.md +48 -0
  4. data/CLAUDE.md +20 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +11 -6
  7. data/README.md +225 -13
  8. data/bin/roast +27 -0
  9. data/docs/INSTRUMENTATION.md +42 -1
  10. data/docs/ITERATION_SYNTAX.md +119 -0
  11. data/examples/conditional/README.md +161 -0
  12. data/examples/conditional/check_condition/prompt.md +1 -0
  13. data/examples/conditional/simple_workflow.yml +15 -0
  14. data/examples/conditional/workflow.yml +23 -0
  15. data/examples/dot_notation/README.md +37 -0
  16. data/examples/dot_notation/workflow.yml +44 -0
  17. data/examples/exit_on_error/README.md +50 -0
  18. data/examples/exit_on_error/analyze_lint_output/prompt.md +9 -0
  19. data/examples/exit_on_error/apply_fixes/prompt.md +2 -0
  20. data/examples/exit_on_error/workflow.yml +19 -0
  21. data/examples/grading/workflow.yml +5 -1
  22. data/examples/iteration/IMPLEMENTATION.md +88 -0
  23. data/examples/iteration/README.md +68 -0
  24. data/examples/iteration/analyze_complexity/prompt.md +22 -0
  25. data/examples/iteration/generate_recommendations/prompt.md +21 -0
  26. data/examples/iteration/generate_report/prompt.md +129 -0
  27. data/examples/iteration/implement_fix/prompt.md +25 -0
  28. data/examples/iteration/prioritize_issues/prompt.md +24 -0
  29. data/examples/iteration/prompts/analyze_file.md +28 -0
  30. data/examples/iteration/prompts/generate_summary.md +24 -0
  31. data/examples/iteration/prompts/update_report.md +29 -0
  32. data/examples/iteration/prompts/write_report.md +22 -0
  33. data/examples/iteration/read_file/prompt.md +9 -0
  34. data/examples/iteration/select_next_issue/prompt.md +25 -0
  35. data/examples/iteration/simple_workflow.md +39 -0
  36. data/examples/iteration/simple_workflow.yml +58 -0
  37. data/examples/iteration/update_fix_count/prompt.md +26 -0
  38. data/examples/iteration/verify_fix/prompt.md +29 -0
  39. data/examples/iteration/workflow.yml +42 -0
  40. data/examples/openrouter_example/workflow.yml +2 -2
  41. data/examples/workflow_generator/README.md +27 -0
  42. data/examples/workflow_generator/analyze_user_request/prompt.md +34 -0
  43. data/examples/workflow_generator/create_workflow_files/prompt.md +32 -0
  44. data/examples/workflow_generator/get_user_input/prompt.md +14 -0
  45. data/examples/workflow_generator/info_from_roast.rb +22 -0
  46. data/examples/workflow_generator/workflow.yml +35 -0
  47. data/lib/roast/errors.rb +9 -0
  48. data/lib/roast/factories/api_provider_factory.rb +61 -0
  49. data/lib/roast/helpers/function_caching_interceptor.rb +1 -1
  50. data/lib/roast/helpers/minitest_coverage_runner.rb +1 -1
  51. data/lib/roast/helpers/prompt_loader.rb +50 -1
  52. data/lib/roast/resources/base_resource.rb +7 -0
  53. data/lib/roast/resources.rb +6 -6
  54. data/lib/roast/tools/ask_user.rb +40 -0
  55. data/lib/roast/tools/cmd.rb +1 -1
  56. data/lib/roast/tools/search_file.rb +1 -1
  57. data/lib/roast/tools/update_files.rb +413 -0
  58. data/lib/roast/tools.rb +12 -1
  59. data/lib/roast/value_objects/api_token.rb +49 -0
  60. data/lib/roast/value_objects/step_name.rb +39 -0
  61. data/lib/roast/value_objects/workflow_path.rb +77 -0
  62. data/lib/roast/value_objects.rb +5 -0
  63. data/lib/roast/version.rb +1 -1
  64. data/lib/roast/workflow/api_configuration.rb +61 -0
  65. data/lib/roast/workflow/base_iteration_step.rb +165 -0
  66. data/lib/roast/workflow/base_step.rb +4 -24
  67. data/lib/roast/workflow/base_workflow.rb +76 -73
  68. data/lib/roast/workflow/command_executor.rb +88 -0
  69. data/lib/roast/workflow/conditional_executor.rb +50 -0
  70. data/lib/roast/workflow/conditional_step.rb +96 -0
  71. data/lib/roast/workflow/configuration.rb +35 -158
  72. data/lib/roast/workflow/configuration_loader.rb +78 -0
  73. data/lib/roast/workflow/configuration_parser.rb +13 -248
  74. data/lib/roast/workflow/context_path_resolver.rb +43 -0
  75. data/lib/roast/workflow/dot_access_hash.rb +198 -0
  76. data/lib/roast/workflow/each_step.rb +86 -0
  77. data/lib/roast/workflow/error_handler.rb +97 -0
  78. data/lib/roast/workflow/expression_utils.rb +36 -0
  79. data/lib/roast/workflow/file_state_repository.rb +3 -2
  80. data/lib/roast/workflow/interpolator.rb +34 -0
  81. data/lib/roast/workflow/iteration_executor.rb +85 -0
  82. data/lib/roast/workflow/llm_boolean_coercer.rb +55 -0
  83. data/lib/roast/workflow/output_handler.rb +35 -0
  84. data/lib/roast/workflow/output_manager.rb +77 -0
  85. data/lib/roast/workflow/parallel_executor.rb +49 -0
  86. data/lib/roast/workflow/repeat_step.rb +75 -0
  87. data/lib/roast/workflow/replay_handler.rb +123 -0
  88. data/lib/roast/workflow/resource_resolver.rb +77 -0
  89. data/lib/roast/workflow/session_manager.rb +6 -2
  90. data/lib/roast/workflow/state_manager.rb +97 -0
  91. data/lib/roast/workflow/step_executor_coordinator.rb +205 -0
  92. data/lib/roast/workflow/step_executor_factory.rb +47 -0
  93. data/lib/roast/workflow/step_executor_registry.rb +79 -0
  94. data/lib/roast/workflow/step_executors/base_step_executor.rb +23 -0
  95. data/lib/roast/workflow/step_executors/hash_step_executor.rb +43 -0
  96. data/lib/roast/workflow/step_executors/parallel_step_executor.rb +54 -0
  97. data/lib/roast/workflow/step_executors/string_step_executor.rb +29 -0
  98. data/lib/roast/workflow/step_finder.rb +97 -0
  99. data/lib/roast/workflow/step_loader.rb +154 -0
  100. data/lib/roast/workflow/step_orchestrator.rb +45 -0
  101. data/lib/roast/workflow/step_runner.rb +23 -0
  102. data/lib/roast/workflow/step_type_resolver.rb +117 -0
  103. data/lib/roast/workflow/workflow_context.rb +60 -0
  104. data/lib/roast/workflow/workflow_executor.rb +90 -209
  105. data/lib/roast/workflow/workflow_initializer.rb +112 -0
  106. data/lib/roast/workflow/workflow_runner.rb +87 -0
  107. data/lib/roast/workflow.rb +3 -0
  108. data/lib/roast.rb +96 -3
  109. data/roast.gemspec +3 -1
  110. data/schema/workflow.json +85 -0
  111. metadata +112 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bdaada020320af4c7fead86184a7cd0b1c06a89e88bc15ac424b31f4b449fb6
4
- data.tar.gz: 3f83f410a1f21992de59b19b8e2f0ea402b9fe50b314b82514723cf20f9a599f
3
+ metadata.gz: 8ab27704514fc6ddfa09003464d2aa324b852379b0548619e2f0023bebe793ae
4
+ data.tar.gz: 18c0936f2b5dc2b54ef420be2ac089b8252f64a02227ab33d98db9d2e6249136
5
5
  SHA512:
6
- metadata.gz: c6dfdd57104e363735a6e24bf5beb43a042340f582f94d8126c3f8a0d30dd92b031c5201a7d3d136bfcd3b7095a51c49329b08c07c5c19544240b18e20ad9948
7
- data.tar.gz: 02aec8d620c3fe0c57d0d4e06790a7513a4a1aa44f68462721b6aa7da3f22f377598b4c00453e4ec825b0adcac3c335d470f945599d39571edb67e8a380597ac
6
+ metadata.gz: 50552385cdb280592a1e331c4a3ec5de2924fa05636af5deb742b96f2fde229e3448e61e6516e570c02a8dc0f416a3b9a3c3d884a800eb89987c90c856a0258d
7
+ data.tar.gz: 8feeb510d87e6e6256c46cbca3e13fbc65701ceb28b049452e5bea2f44815f7770e688f8422487b431a85c5f459beffadcce590e7b860cde8a1ab4ee939ff50e
@@ -16,7 +16,7 @@ jobs:
16
16
  fail-fast: false
17
17
  matrix:
18
18
  os: [ubuntu]
19
- ruby: ['3.4']
19
+ ruby: ['3.2', '3.3', '3.4']
20
20
  runs-on: ${{ matrix.os }}-latest
21
21
  continue-on-error: ${{ matrix.ruby == 'ruby-head' }}
22
22
  steps:
data/CHANGELOG.md CHANGED
@@ -5,6 +5,54 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.0] - 2025-05-26
9
+
10
+ ### Added
11
+ - Conditional execution support with `if` and `unless` clauses for workflow steps
12
+ - Iteration mechanisms for workflows with `repeat` and `each` constructs (resolving issue #48)
13
+ - Support for conditional repetition with `until` condition and safety limits
14
+ - Collection iteration with variable binding for processing lists of items
15
+ - State persistence for loop iterations to enable resumption after failure
16
+ - Standardized evaluation of Ruby expressions in iteration constructs using `{{}}` syntax
17
+ - Support for using bash commands, step names, and Ruby expressions in iteration conditions and collections
18
+ - Intelligent LLM response to boolean conversion with pattern-based recognition for natural language responses
19
+ - `exit_on_error` configuration option for command steps to continue workflow on failure (resolving issue #71)
20
+ - Dot notation access for workflow outputs (e.g., `workflow.output.step.field`)
21
+ - `--pause` flag for stepping through workflow execution interactively
22
+
23
+ ### Fixed
24
+ - Automatically add `.gitignore` file to cache directory when created (completing issue #22)
25
+ - Load initializers before trying to load tools in case custom tools are defined in initializers (thanks @palkan)
26
+ - Fix loading of targetless workflows (thanks @palkan)
27
+ - Fix OpenRouter support (thanks @xrendan)
28
+ - API authentication error handling and model access issues
29
+ - Conditional step transcript replay regression
30
+ - DotAccessHash serialization for AI prompts
31
+
32
+ ### Improved
33
+ - Enhanced search file tool logging to show full expanded paths instead of relative paths
34
+ - Major refactoring to eliminate circular dependencies and improve architecture
35
+ - Extracted command execution logic into dedicated CommandExecutor class
36
+ - Separated conditional execution from iteration logic for better SOLID compliance
37
+ - Enhanced error messages for API authentication failures
38
+ - Replaced all `require_relative` with `require` statements for consistency
39
+
40
+ ### Changed
41
+ - Refactored god objects to improve code organization and maintainability
42
+ - Improved separation of concerns between workflow components
43
+
44
+ [0.2.0]: https://github.com/Shopify/roast/compare/v0.1.7...v0.2.0
45
+
46
+ ## [0.1.7] - 2024-05-16
47
+
48
+ ### Added
49
+ - `UpdateFiles` tool for applying diffs/patches to multiple files at once
50
+ - Support for atomic file updates with rollback capability
51
+ - Comprehensive documentation for all built-in tools
52
+ - Enhanced README with detailed tool usage examples
53
+
54
+ ``[0.1.7]: https://github.com/Shopify/roast/compare/v0.1.6...v0.1.7
55
+
8
56
  ## [0.1.6] - 2024-05-15
9
57
 
10
58
  ### Added
data/CLAUDE.md CHANGED
@@ -12,10 +12,14 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
12
12
  - Run single test: `bundle exec ruby -Itest test/path/to/test_file.rb`
13
13
  - Lint: `bundle exec rubocop`
14
14
  - Lint (with autocorrect, preferred): `bundle exec rubocop -A`
15
+ - Whenever you want to run the whole test suite just run `bundle exec rake` to also run linting, and note the linting errors too (most will auto correct but not all)
16
+ - **Run roast locally**: Use `bin/roast` (not `bundle exec roast` which may use the installed gem)
17
+ - Alternative: `bundle exec exe/roast`
15
18
 
16
19
  ## Tech stack
17
20
  - `thor` and `cli-ui` for the CLI tool
18
21
  - Testing: Use Minitest, VCR for HTTP mocking, test files named with `_test.rb` suffix
22
+ - Prefer using the more literate `test "this is a test description" do` type of testing that we get from extending ActiveSupport::TestCase over the primitive XUnit-style def test_description headings for tests
19
23
 
20
24
  ## Code Style Guidelines
21
25
 
@@ -30,6 +34,22 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
30
34
  - Add runtime dependencies to `roast.gemspec`.
31
35
  - Add development dependencies to `Gemfile`.
32
36
  - Don't ever test private methods directly. Specs should test behavior, not implementation.
37
+ - I do not like test-specific code embedded in production code, don't ever do that
38
+ - **Do not use require_relative**
39
+ - Require statements should always be in alphabetical order
40
+ - Always leave a blank line after module includes and before the rest of the class
41
+
42
+ ## Architecture Guidelines
43
+
44
+ - **Maintain proper separation of concerns**: Don't mix unrelated concepts in the same class or module
45
+ - Example: Conditional execution (if/unless) should NOT be mixed with iteration execution (each/repeat)
46
+ - Each concept should have its own executor class and be handled separately
47
+ - **Use appropriate inheritance**: Only inherit from a base class if the child truly "is-a" type of the parent
48
+ - Don't inherit just to reuse some methods - use composition instead
49
+ - **Follow Single Responsibility Principle**: Each class should have one reason to change
50
+ - IterationExecutor handles iterations (each, repeat)
51
+ - ConditionalExecutor handles conditionals (if, unless)
52
+ - Don't combine different responsibilities in one class
33
53
 
34
54
  ## Git Workflow Practices
35
55
 
data/Gemfile CHANGED
@@ -8,6 +8,7 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
8
8
  gemspec
9
9
 
10
10
  gem "cgi"
11
+ gem "cli-ui"
11
12
  gem "dotenv"
12
13
  gem "guard"
13
14
  gem "guard-minitest"
data/Gemfile.lock CHANGED
@@ -1,11 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- roast-ai (0.1.6)
4
+ roast-ai (0.2.0)
5
5
  activesupport (~> 8.0)
6
+ cli-ui
7
+ diff-lcs (~> 1.5)
6
8
  faraday-retry
7
9
  json-schema
8
- raix (~> 0.8.4)
10
+ raix (~> 0.8.6)
9
11
  thor (~> 1.3)
10
12
 
11
13
  GEM
@@ -31,16 +33,18 @@ GEM
31
33
  benchmark (0.4.0)
32
34
  bigdecimal (3.1.9)
33
35
  cgi (0.4.2)
36
+ cli-ui (2.3.1)
34
37
  coderay (1.1.3)
35
38
  concurrent-ruby (1.3.5)
36
- connection_pool (2.5.1)
39
+ connection_pool (2.5.3)
37
40
  crack (1.0.0)
38
41
  bigdecimal
39
42
  rexml
43
+ diff-lcs (1.6.1)
40
44
  dotenv (3.1.8)
41
45
  drb (2.2.1)
42
46
  event_stream_parser (1.0.0)
43
- faraday (2.13.0)
47
+ faraday (2.13.1)
44
48
  faraday-net_http (>= 2.0, < 3.5)
45
49
  json
46
50
  logger
@@ -72,7 +76,7 @@ GEM
72
76
  hashdiff (1.1.2)
73
77
  i18n (1.14.7)
74
78
  concurrent-ruby (~> 1.0)
75
- json (2.10.2)
79
+ json (2.12.0)
76
80
  json-schema (5.1.1)
77
81
  addressable (~> 2.8)
78
82
  bigdecimal (~> 3.1)
@@ -111,7 +115,7 @@ GEM
111
115
  public_suffix (6.0.1)
112
116
  racc (1.8.1)
113
117
  rainbow (3.1.1)
114
- raix (0.8.4)
118
+ raix (0.8.6)
115
119
  activesupport (>= 6.0)
116
120
  faraday-retry (~> 2.0)
117
121
  open_router (~> 0.2)
@@ -166,6 +170,7 @@ PLATFORMS
166
170
 
167
171
  DEPENDENCIES
168
172
  cgi
173
+ cli-ui
169
174
  dotenv
170
175
  guard
171
176
  guard-minitest
data/README.md CHANGED
@@ -46,7 +46,7 @@ Each step can have its own prompt file (e.g., `analyze_coverage/prompt.md`) and
46
46
  ```yaml
47
47
  steps:
48
48
  - prepare_data
49
- -
49
+ -
50
50
  - analyze_code_quality
51
51
  - check_test_coverage
52
52
  - verify_documentation
@@ -86,21 +86,21 @@ In Roast, workflows maintain a single conversation with the AI model throughout
86
86
 
87
87
  Roast supports several types of steps:
88
88
 
89
- 1. **Standard step**: References a directory containing at least a `prompt.md` and optional `output.txt` template. This is the most common type of step.
89
+ 1. **Standard step**: References a directory containing at least a `prompt.md` and optional `output.txt` template. This is the most common type of step.
90
90
  ```yaml
91
91
  steps:
92
92
  - analyze_code
93
93
  ```
94
94
 
95
95
  As an alternative to a directory, you can also implement a custom step as a Ruby class, optionally extending `Roast::Workflow::BaseStep`.
96
-
96
+
97
97
  In the example given above, the script would live at `workflow/analyze_code.rb` and should contain a class named `AnalyzeCode` with an initializer that takes a workflow object as context, and a `call` method that will be invoked to run the step. The result of the `call` method will be stored in the `workflow.output` hash.
98
98
 
99
99
 
100
100
  2. **Parallel steps**: Groups of steps executed concurrently
101
101
  ```yaml
102
102
  steps:
103
- -
103
+ -
104
104
  - analyze_code_quality
105
105
  - check_test_coverage
106
106
  ```
@@ -113,7 +113,72 @@ Roast supports several types of steps:
113
113
  ```
114
114
  This will execute the command and store the result in the workflow output hash. Explicit key name is optional (`rubocop` in the second line of the example).
115
115
 
116
- 4. **Raw prompt step**: Simple text prompts for the model without tools
116
+ By default, commands that exit with non-zero status will halt the workflow. You can configure steps to continue on error:
117
+ ```yaml
118
+ steps:
119
+ - lint_check: $(rubocop {{file}})
120
+ - fix_issues
121
+
122
+ # Step configuration
123
+ lint_check:
124
+ exit_on_error: false # Continue workflow even if command fails
125
+ ```
126
+ When `exit_on_error: false`, the command output will include the exit status, allowing subsequent steps to process error information.
127
+
128
+ 4. **Conditional steps**: Execute different steps based on conditions using `if/unless`
129
+ ```yaml
130
+ steps:
131
+ - check_environment:
132
+ if: "{{ENV['RAILS_ENV'] == 'production'}}"
133
+ then:
134
+ - run_production_checks
135
+ - notify_team
136
+ else:
137
+ - run_development_setup
138
+
139
+ - verify_dependencies:
140
+ unless: "$(bundle check)"
141
+ then:
142
+ - bundle_install: "$(bundle install)"
143
+ ```
144
+
145
+ Conditions can be:
146
+ - Ruby expressions: `if: "{{output['count'] > 5}}"`
147
+ - Bash commands: `if: "$(test -f config.yml && echo true)"` (exit code 0 = true)
148
+ - Step references: `if: "previous_step_name"` (uses the step's output)
149
+ - Direct values: `if: "true"` or `if: "false"`
150
+
151
+ 5. **Iteration steps**: Loop over collections or repeat steps with conditions
152
+ ```yaml
153
+ steps:
154
+ # Loop over a collection
155
+ - process_files:
156
+ each: "{{Dir.glob('**/*.rb')}}"
157
+ as: current_file
158
+ steps:
159
+ - analyze_file
160
+ - Generate a report for {{current_file}}
161
+
162
+ # Repeat until a condition is met
163
+ - improve_code:
164
+ repeat:
165
+ until: "{{output['test_pass'] == true}}"
166
+ max_iterations: 5
167
+ steps:
168
+ - run_tests
169
+ - fix_issues
170
+ ```
171
+
172
+ Each loops support:
173
+ - Collections from Ruby expressions: `each: "{{[1, 2, 3]}}"`
174
+ - Command output: `each: "$(ls *.rb)"`
175
+ - Step references: `each: "file_list"`
176
+
177
+ Repeat loops support:
178
+ - Until conditions: `until: "{{condition}}"`
179
+ - Maximum iterations: `max_iterations: 10`
180
+
181
+ 6. **Raw prompt step**: Simple text prompts for the model without tools
117
182
  ```yaml
118
183
  steps:
119
184
  - Summarize the changes made to the codebase.
@@ -139,7 +204,7 @@ Roast handles data flow between steps in three primary ways:
139
204
  - Generate a summary for {{file}}
140
205
  - result_for_{{file}}: store_results
141
206
  ```
142
-
207
+
143
208
  Interpolation supports:
144
209
  - Simple variable access: `{{file}}`, `{{resource.target}}`
145
210
  - Access to step outputs: `{{output['previous_step']}}`
@@ -150,7 +215,7 @@ For typical AI workflows, the continuous conversation history provides seamless
150
215
  ### Command Line Options
151
216
 
152
217
  #### Basic Options
153
- - `-o, --output FILE`: Save results to a file instead of outputting to STDOUT
218
+ - `-o, --output FILE`: Save results to a file instead of outputting to STDOUT
154
219
  - `-c, --concise`: Use concise output templates (exposed as a boolean flag on `workflow`)
155
220
  - `-v, --verbose`: Show output from all steps as they execute
156
221
  - `-r, --replay STEP_NAME`: Resume a workflow from a specific step, optionally with a specific session timestamp
@@ -241,7 +306,7 @@ roast execute workflow.yml -t "$(find . -name '*.rb' -mtime -1)"
241
306
  # Process changed test files
242
307
  roast execute workflow.yml -t "$(git diff --name-only HEAD | grep _test.rb)"
243
308
 
244
- # Process staged files
309
+ # Process staged files
245
310
  roast execute workflow.yml -t "$(git diff --cached --name-only)"
246
311
  ```
247
312
 
@@ -255,7 +320,7 @@ name: API Integration Workflow
255
320
  tools:
256
321
  - Roast::Tools::ReadFile
257
322
  - Roast::Tools::WriteFile
258
-
323
+
259
324
  # Dynamic API token using shell command
260
325
  api_token: $(cat ~/.my_token)
261
326
 
@@ -349,7 +414,9 @@ api_provider: openrouter
349
414
  api_token: $(echo $OPENROUTER_API_KEY)
350
415
  ```
351
416
 
352
- This makes it easy to use environment-specific tokens without hardcoding credentials, especially useful in development environments or CI/CD pipelines.
417
+
418
+ This makes it easy to use environment-specific tokens without hardcoding credentials, especially useful in development environments or CI/CD pipelines. Alternatively, Roast will fall back to `OPENROUTER_API_KEY` or `OPENAI_API_KEY` environment variables based on the specified provider.
419
+
353
420
 
354
421
  ### Template Output with ERB
355
422
 
@@ -372,7 +439,7 @@ This is an example of where the `workflow.output` hash is useful - formatting ou
372
439
 
373
440
  Available in templates:
374
441
  - `response`: The AI's response for this step
375
- - `workflow`: Access to the workflow object
442
+ - `workflow`: Access to the workflow object
376
443
  - `workflow.output`: The shared hash containing results from all steps when you need programmatic access
377
444
  - `workflow.file`: Current file being processed (or `nil` for targetless workflows)
378
445
  - All workflow configuration options
@@ -385,6 +452,151 @@ For most workflows, you'll mainly use `response` to access the current step's re
385
452
 
386
453
  Roast provides extensive instrumentation capabilities using ActiveSupport::Notifications. You can monitor workflow execution, track AI model usage, measure performance, and integrate with external monitoring systems. [Read the full instrumentation documentation](docs/INSTRUMENTATION.md).
387
454
 
455
+ ### Built-in Tools
456
+
457
+ Roast provides several built-in tools that you can use in your workflows:
458
+
459
+ #### ReadFile
460
+
461
+ Reads the contents of a file from the filesystem.
462
+
463
+ ```ruby
464
+ # Basic usage
465
+ read_file(path: "path/to/file.txt")
466
+
467
+ # Reading a specific portion of a file
468
+ read_file(path: "path/to/large_file.txt", offset: 100, limit: 50)
469
+ ```
470
+
471
+ - The `path` can be absolute or relative to the current working directory
472
+ - Use `offset` and `limit` for large files to read specific sections (line numbers)
473
+ - Returns the file content as a string
474
+
475
+ #### WriteFile
476
+
477
+ Writes content to a file, creating the file if it doesn't exist or overwriting it if it does.
478
+
479
+ ```ruby
480
+ # Basic usage
481
+ write_file(path: "output.txt", content: "This is the file content")
482
+
483
+ # With path restriction for security
484
+ write_file(
485
+ path: "output.txt",
486
+ content: "Restricted content",
487
+ restrict: "/safe/directory" # Only allows writing to files under this path
488
+ )
489
+ ```
490
+
491
+ - Creates missing directories automatically
492
+ - Can restrict file operations to specific directories for security
493
+ - Returns a success message with the number of lines written
494
+
495
+ #### UpdateFiles
496
+
497
+ Applies a unified diff/patch to one or more files. Changes are applied atomically when possible.
498
+
499
+ ```ruby
500
+ update_files(
501
+ diff: <<~DIFF,
502
+ --- a/file1.txt
503
+ +++ b/file1.txt
504
+ @@ -1,3 +1,4 @@
505
+ line1
506
+ +new line
507
+ line2
508
+ line3
509
+
510
+ --- a/file2.txt
511
+ +++ b/file2.txt
512
+ @@ -5,7 +5,7 @@
513
+ line5
514
+ line6
515
+ -old line7
516
+ +updated line7
517
+ line8
518
+ DIFF
519
+ base_path: "/path/to/project", # Optional, defaults to current working directory
520
+ restrict_path: "/path/to/allowed", # Optional, restricts where files can be modified
521
+ create_files: true, # Optional, defaults to true
522
+ )
523
+ ```
524
+
525
+ - Accepts standard unified diff format from tools like `git diff`
526
+ - Supports multiple file changes in a single operation
527
+ - Handles file creation, deletion, and modification
528
+ - Performs atomic operations with rollback on failure
529
+ - Includes fuzzy matching to handle minor context differences
530
+ - This tool is especially useful for making targeted changes to multiple files at once
531
+
532
+ #### Grep
533
+
534
+ Searches file contents for a specific pattern using regular expressions.
535
+
536
+ ```ruby
537
+ # Basic usage
538
+ grep(pattern: "function\\s+myFunction")
539
+
540
+ # With file filtering
541
+ grep(pattern: "class\\s+User", include: "*.rb")
542
+
543
+ # With directory scope
544
+ grep(pattern: "TODO:", path: "src/components")
545
+ ```
546
+
547
+ - Uses regular expressions for powerful pattern matching
548
+ - Can filter by file types using the `include` parameter
549
+ - Can scope searches to specific directories with the `path` parameter
550
+ - Returns a list of files containing matches
551
+
552
+ #### SearchFile
553
+
554
+ Provides advanced file search capabilities beyond basic pattern matching.
555
+
556
+ ```ruby
557
+ search_file(query: "class User", file_path: "app/models")
558
+ ```
559
+
560
+ - Combines pattern matching with contextual search
561
+ - Useful for finding specific code structures or patterns
562
+ - Returns matched lines with context
563
+
564
+ #### Cmd
565
+
566
+ Executes shell commands and returns their output.
567
+
568
+ ```ruby
569
+ # Execute a simple command
570
+ cmd(command: "ls -la")
571
+
572
+ # With working directory specified
573
+ cmd(command: "npm list", cwd: "/path/to/project")
574
+
575
+ # With environment variables
576
+ cmd(command: "deploy", env: { "NODE_ENV" => "production" })
577
+ ```
578
+
579
+ - Provides access to shell commands for more complex operations
580
+ - Can specify working directory and environment variables
581
+ - Captures and returns command output
582
+ - Useful for integrating with existing tools and scripts
583
+
584
+ #### CodingAgent
585
+
586
+ Creates a specialized agent for complex coding tasks or long-running operations.
587
+
588
+ ```ruby
589
+ coding_agent(
590
+ task: "Refactor the authentication module to use JWT tokens",
591
+ language: "ruby",
592
+ files: ["app/models/user.rb", "app/controllers/auth_controller.rb"]
593
+ )
594
+ ```
595
+
596
+ - Delegates complex tasks to a specialized coding agent
597
+ - Useful for tasks that require deep code understanding or multi-step changes
598
+ - Can work across multiple files and languages
599
+
388
600
  ### Custom Tools
389
601
 
390
602
  You can create your own tools using the [Raix function dispatch pattern](https://github.com/OlympiaAI/raix-rails?tab=readme-ov-file#use-of-toolsfunctions). Custom tools should be placed in `.roast/initializers/` (subdirectories are supported):
@@ -411,11 +623,11 @@ module MyProject
411
623
 
412
624
  def call(commit_sha, include_diff = false)
413
625
  Roast::Helpers::Logger.info("🔍 Analyzing commit: #{commit_sha}\n")
414
-
626
+
415
627
  # Your implementation here
416
628
  commit_info = `git show #{commit_sha} --stat`
417
629
  commit_info += "\n\n" + `git show #{commit_sha}` if include_diff
418
-
630
+
419
631
  commit_info
420
632
  rescue StandardError => e
421
633
  "Error analyzing commit: #{e.message}".tap do |error_message|
data/bin/roast ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'roast' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../.ruby-lsp/Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("roast-ai", "roast")
@@ -199,4 +199,45 @@ Then run:
199
199
  roast execute test_instrumentation.yml some_file.rb
200
200
  ```
201
201
 
202
- Your instrumentation should capture the workflow start, step execution, and workflow completion events.
202
+ Your instrumentation should capture the workflow start, step execution, and workflow completion events.
203
+
204
+ ## Available Tools
205
+
206
+ Roast provides several built-in tools that you can use in your workflows:
207
+
208
+ ### WriteFile Tool
209
+
210
+ Writes content to a file, creating the file if it doesn't exist or overwriting it if it does.
211
+
212
+ ```ruby
213
+ # Example usage in a prompt
214
+ write_file(path: "output.txt", content: "This is the file content")
215
+ ```
216
+
217
+ ### UpdateFiles Tool
218
+
219
+ Applies a unified diff/patch to one or more files. Changes are applied atomically when possible.
220
+
221
+ ```ruby
222
+ # Example usage in a prompt
223
+ update_files(diff: <<~DIFF, base_path: "/path/to/project", create_files: true)
224
+ --- a/file1.txt
225
+ +++ b/file1.txt
226
+ @@ -1,3 +1,4 @@
227
+ line1
228
+ +new line
229
+ line2
230
+ line3
231
+
232
+ --- a/file2.txt
233
+ +++ b/file2.txt
234
+ @@ -5,7 +5,7 @@
235
+ line5
236
+ line6
237
+ -old line7
238
+ +updated line7
239
+ line8
240
+ DIFF
241
+ ```
242
+
243
+ This tool is especially useful for making targeted changes to multiple files at once, without having to replace entire file contents.