assistant 0.0.2 → 1.0.0.rc1

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +13 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +39 -0
  4. data/.github/dependabot.yml +4 -0
  5. data/.github/workflows/ci.yml +140 -0
  6. data/.github/workflows/docs.yml +64 -0
  7. data/.github/workflows/release.yml +46 -0
  8. data/.gitignore +5 -1
  9. data/.markdownlint.json +6 -0
  10. data/.opencode/.gitignore +4 -0
  11. data/.opencode/opencode.json +13 -0
  12. data/.opencode/skills/create-pr/SKILL.md +138 -0
  13. data/.opencode/skills/ruby-services/SKILL.md +81 -0
  14. data/.rubocop.yml +40 -148
  15. data/.ruby-version +1 -1
  16. data/.yardopts +17 -0
  17. data/CHANGELOG.md +434 -0
  18. data/CONTRIBUTING.md +131 -0
  19. data/Gemfile +10 -0
  20. data/Gemfile.lock +264 -94
  21. data/README.md +125 -16
  22. data/Rakefile +53 -3
  23. data/SECURITY.md +50 -0
  24. data/Steepfile +49 -0
  25. data/_config.yml +87 -0
  26. data/assistant.gemspec +33 -20
  27. data/docs/api-reference.md +264 -0
  28. data/docs/changelog.md +26 -0
  29. data/docs/deprecations.md +86 -0
  30. data/docs/examples/cli-handler.md +17 -0
  31. data/docs/examples/composing-services.md +17 -0
  32. data/docs/examples/execute-callbacks.md +17 -0
  33. data/docs/examples/index.md +29 -0
  34. data/docs/examples/instrumentation-notifier.md +17 -0
  35. data/docs/examples/rails-service.md +17 -0
  36. data/docs/examples/rbs-generator.md +17 -0
  37. data/docs/examples/sidekiq-worker.md +17 -0
  38. data/docs/getting-started.md +136 -0
  39. data/docs/guides/composing-services.md +222 -0
  40. data/docs/guides/index.md +25 -0
  41. data/docs/guides/inputs.md +333 -0
  42. data/docs/guides/logging-and-results.md +202 -0
  43. data/docs/guides/rbs-and-types.md +16 -0
  44. data/docs/guides/validation.md +180 -0
  45. data/docs/index.md +69 -0
  46. data/docs/roadmap.md +33 -0
  47. data/exe/assistant-rbs +7 -0
  48. data/lib/assistant/execute_callbacks.rb +103 -0
  49. data/lib/assistant/execute_callbacks.rbs +30 -0
  50. data/lib/assistant/input_builder/accessors.rb +36 -0
  51. data/lib/assistant/input_builder/accessors.rbs +10 -0
  52. data/lib/assistant/input_builder/default_option.rb +41 -0
  53. data/lib/assistant/input_builder/default_option.rbs +11 -0
  54. data/lib/assistant/input_builder/dsl.rb +37 -0
  55. data/lib/assistant/input_builder/dsl.rbs +12 -0
  56. data/lib/assistant/input_builder/optional_option.rb +45 -0
  57. data/lib/assistant/input_builder/optional_option.rbs +10 -0
  58. data/lib/assistant/input_builder/registry.rb +27 -0
  59. data/lib/assistant/input_builder/registry.rbs +13 -0
  60. data/lib/assistant/input_builder/require_validator.rb +104 -0
  61. data/lib/assistant/input_builder/require_validator.rbs +24 -0
  62. data/lib/assistant/input_builder/type_validator.rb +47 -0
  63. data/lib/assistant/input_builder/type_validator.rbs +18 -0
  64. data/lib/assistant/input_builder.rb +28 -0
  65. data/lib/assistant/input_builder.rbs +15 -0
  66. data/lib/assistant/log_item.rb +75 -17
  67. data/lib/assistant/log_item.rbs +40 -0
  68. data/lib/assistant/log_list.rb +44 -12
  69. data/lib/assistant/log_list.rbs +48 -0
  70. data/lib/assistant/rbs_generator/cli.rb +109 -0
  71. data/lib/assistant/rbs_generator/cli.rbs +24 -0
  72. data/lib/assistant/rbs_generator/renderer.rb +67 -0
  73. data/lib/assistant/rbs_generator/renderer.rbs +11 -0
  74. data/lib/assistant/rbs_generator/writer.rb +65 -0
  75. data/lib/assistant/rbs_generator/writer.rbs +24 -0
  76. data/lib/assistant/rbs_generator.rb +38 -0
  77. data/lib/assistant/rbs_generator.rbs +5 -0
  78. data/lib/assistant/refinements/string_blankness.rb +14 -0
  79. data/lib/assistant/refinements/string_blankness.rbs +6 -0
  80. data/lib/assistant/service.rb +328 -8
  81. data/lib/assistant/service.rbs +86 -0
  82. data/lib/assistant/version.rb +5 -1
  83. data/lib/assistant/version.rbs +5 -0
  84. data/lib/assistant.rb +53 -4
  85. data/lib/assistant.rbs +25 -0
  86. data/mise.toml +6 -0
  87. data/sig/examples/greeter.rbs +14 -0
  88. metadata +128 -112
  89. data/.circleci/config.yml +0 -45
  90. data/.fasterer.yml +0 -19
  91. data/.rspec +0 -3
  92. data/.rubocop_todo.yml +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57d148f4abcc7a6b10a3641ca2e75b0b4dfe0141a6536f062f1c8665f6bf5e2f
4
- data.tar.gz: eed5fdf9f3e02724a342b109d8ef14e50b8b3fd359074ab5bb2475d1a08d88b0
3
+ metadata.gz: 6b4eab141f258e58024dcc2805a4030321835b45853cf915d8a8c48aa9849144
4
+ data.tar.gz: 354914c47054404c57ef636d46316e0ee8cb491305ab9c081a0628e4a30708c5
5
5
  SHA512:
6
- metadata.gz: a067fca9874e1eae78d65c49fe3b583e186a8a19e0c08c31128683a7e351758f4c839edf0a70cb0bb2feb01521b55bc4d74782e4bfaf51272d7736daad44b517
7
- data.tar.gz: 721b623f02e50b972bc9eb58ee25640e3d5092195c57d4e5f0f0c79bcb093eee82d49d1d0ebc84c5493af1a04755df6996c212edc055b35c21b6e68c99ff73d6
6
+ metadata.gz: ced1f45ddcc684272b2858aebead07ee968823cdf0c52bf71877cf283b1881fec66e59b7f9c56538d5c9ba949abac3c425083c1334947bc0572235dea1ed0b92
7
+ data.tar.gz: 64bde79e3880ac363fc31e0d37dcae5e4e3657ec4f55807385378e3f59699fb211204a1fdf8339d4e8dc9e5d4ce8dad1bb71e82d5c6b845c1697dbc136cc99ba
data/.editorconfig ADDED
@@ -0,0 +1,13 @@
1
+ # EditorConfig is awesome: https://EditorConfig.org
2
+
3
+ # top-most EditorConfig file
4
+ root = true
5
+
6
+ [*]
7
+ indent_style = space
8
+ indent_size = 2
9
+ end_of_line = lf
10
+ charset = utf-8
11
+ trim_trailing_whitespace = true
12
+ insert_final_newline = true
13
+ quote_type = single
@@ -0,0 +1,39 @@
1
+ <!-- markdownlint-disable MD013 -->
2
+ ## Scope
3
+
4
+ <!--
5
+ Which roadmap milestone or issue does this PR implement?
6
+ Link the relevant `docs/v1/*.md` line or the GitHub issue.
7
+ -->
8
+
9
+ ## What this PR ships
10
+
11
+ <!--
12
+ Bullet list of the public-facing changes.
13
+ -->
14
+
15
+ -
16
+
17
+ ## Verification
18
+
19
+ <!--
20
+ Paste the tail of the local pipeline (or just confirm rake ci is green).
21
+
22
+ ```sh
23
+ bundle exec rake ci
24
+ ```
25
+ -->
26
+
27
+ ## Out of scope
28
+
29
+ <!--
30
+ Anything that was deliberately left for a follow-up PR.
31
+ -->
32
+
33
+ ## Checklist
34
+
35
+ - [ ] `CHANGELOG.md` entry added under `[Unreleased]`.
36
+ - [ ] Tests added or updated under `test/`.
37
+ - [ ] Docs updated under `docs/` (and the relevant `docs/v1/*.md` checkbox
38
+ flipped if a roadmap item is closing).
39
+ - [ ] `bundle exec rake ci` is green locally.
@@ -9,3 +9,7 @@ updates:
9
9
  directory: "/" # Location of package manifests
10
10
  schedule:
11
11
  interval: "weekly"
12
+ - package-ecosystem: "github-actions"
13
+ directory: "/"
14
+ schedule:
15
+ interval: "weekly"
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: CI
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ # Default to least privilege; jobs may opt into more.
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ test:
16
+ name: Minitest (Ruby ${{ matrix.ruby }})
17
+ runs-on: ubuntu-latest
18
+ strategy:
19
+ fail-fast: false
20
+ matrix:
21
+ ruby: ['3.4', '4.0']
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby }}
27
+ bundler-cache: true
28
+ - name: Run tests
29
+ run: bundle exec rake test
30
+
31
+ rubocop:
32
+ name: RuboCop
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: ruby/setup-ruby@v1
37
+ with:
38
+ ruby-version: '4.0'
39
+ bundler-cache: true
40
+ - name: Run RuboCop
41
+ run: bundle exec rubocop --parallel
42
+
43
+ steep:
44
+ name: Steep
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ - uses: ruby/setup-ruby@v1
49
+ with:
50
+ ruby-version: '3.4'
51
+ bundler-cache: true
52
+ - name: Run Steep
53
+ run: bundle exec steep check --jobs=1
54
+
55
+ coverage:
56
+ name: Coverage (SimpleCov)
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ - uses: ruby/setup-ruby@v1
61
+ with:
62
+ ruby-version: '4.0'
63
+ bundler-cache: true
64
+ - name: Run tests with SimpleCov
65
+ run: bundle exec rake test
66
+ - name: Append coverage summary
67
+ if: always()
68
+ run: |
69
+ ruby -rjson -e '
70
+ path = "coverage/.last_run.json"
71
+ unless File.exist?(path)
72
+ warn "no coverage/.last_run.json produced"
73
+ exit 0
74
+ end
75
+ data = JSON.parse(File.read(path))
76
+ line = data.dig("result", "line")
77
+ branch = data.dig("result", "branch")
78
+ File.open(ENV.fetch("GITHUB_STEP_SUMMARY"), "a") do |f|
79
+ f.puts "## SimpleCov coverage"
80
+ f.puts
81
+ f.puts "| Metric | Coverage | Soft target |"
82
+ f.puts "| ------ | -------- | ----------- |"
83
+ f.puts "| Line | #{line}% | >= 98% |"
84
+ f.puts "| Branch | #{branch}% | >= 95% |"
85
+ f.puts
86
+ f.puts "Reported only; not enforced in CI. See docs/v1/05-quality-and-tooling.md."
87
+ end
88
+ '
89
+ - name: Upload coverage HTML artifact
90
+ if: always()
91
+ uses: actions/upload-artifact@v7
92
+ with:
93
+ name: coverage-html
94
+ path: coverage/
95
+ if-no-files-found: warn
96
+
97
+ runtime-deps:
98
+ name: Runtime deps assertion (zero)
99
+ runs-on: ubuntu-latest
100
+ steps:
101
+ - uses: actions/checkout@v4
102
+ - uses: ruby/setup-ruby@v1
103
+ with:
104
+ ruby-version: '3.4'
105
+ - name: Assert assistant.gemspec declares zero runtime dependencies
106
+ run: |
107
+ ruby -e '
108
+ spec = Gem::Specification.load("assistant.gemspec")
109
+ deps = spec.runtime_dependencies.map(&:name)
110
+ if deps.empty?
111
+ puts "OK: assistant has zero runtime dependencies."
112
+ else
113
+ warn "FAIL: unexpected runtime dependencies: #{deps.join(", ")}"
114
+ exit 1
115
+ end
116
+ '
117
+
118
+ bin-smoke:
119
+ name: bin/ scripts smoke
120
+ runs-on: ubuntu-latest
121
+ steps:
122
+ - uses: actions/checkout@v4
123
+ - uses: ruby/setup-ruby@v1
124
+ with:
125
+ ruby-version: '3.4'
126
+ # Intentionally no bundler-cache: bin/setup is the thing under
127
+ # test; we want it to drive the bundle install end-to-end on a
128
+ # cold checkout.
129
+ - name: bin/setup smoke (cold bundle install)
130
+ run: ./bin/setup
131
+ - name: Syntax check bin/ scripts
132
+ run: |
133
+ bash -n bin/setup
134
+ ruby -c bin/console
135
+ ruby -c bin/version
136
+ - name: bin/version --help smoke
137
+ run: bundle exec bin/version --help
138
+ - name: bin/console loads assistant
139
+ run: |
140
+ echo 'puts Assistant::VERSION; exit' | bundle exec bin/console
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: Docs
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ paths:
8
+ - docs/**
9
+ - _config.yml
10
+ - Gemfile
11
+ - Gemfile.lock
12
+ - .github/workflows/docs.yml
13
+ pull_request:
14
+ branches: [main]
15
+ paths:
16
+ - docs/**
17
+ - _config.yml
18
+ - Gemfile
19
+ - Gemfile.lock
20
+ - .github/workflows/docs.yml
21
+ workflow_dispatch:
22
+
23
+ permissions:
24
+ contents: read
25
+
26
+ concurrency:
27
+ group: pages
28
+ cancel-in-progress: false
29
+
30
+ jobs:
31
+ build:
32
+ name: jekyll build --strict_front_matter
33
+ runs-on: ubuntu-latest
34
+ env:
35
+ BUNDLE_WITH: docs
36
+ JEKYLL_ENV: production
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ - uses: ruby/setup-ruby@v1
40
+ with:
41
+ ruby-version: '3.4'
42
+ bundler-cache: true
43
+ - name: Build site
44
+ run: bundle exec jekyll build --strict_front_matter --baseurl "/assistant"
45
+ - name: Upload site artifact
46
+ uses: actions/upload-pages-artifact@v3
47
+ with:
48
+ path: _site
49
+
50
+ deploy:
51
+ name: Deploy to GitHub Pages
52
+ needs: build
53
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
54
+ runs-on: ubuntu-latest
55
+ permissions:
56
+ pages: write
57
+ id-token: write
58
+ environment:
59
+ name: github-pages
60
+ url: ${{ steps.deployment.outputs.page_url }}
61
+ steps:
62
+ - name: Deploy
63
+ id: deployment
64
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: Release
3
+
4
+ on:
5
+ push:
6
+ tags:
7
+ - 'v*.*.*'
8
+ workflow_dispatch:
9
+
10
+ # Default to least privilege; the release job opts into the perms it needs.
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ release:
16
+ name: Build and publish gem
17
+ runs-on: ubuntu-latest
18
+ environment: rubygems
19
+ permissions:
20
+ contents: write
21
+ id-token: write
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: '4.0'
27
+ bundler-cache: true
28
+
29
+ - name: Run tests before publishing
30
+ run: bundle exec rake test
31
+
32
+ - name: Configure trusted publishing
33
+ uses: rubygems/configure-rubygems-credentials@v2.1.0
34
+
35
+ - name: Build gem
36
+ run: gem build assistant.gemspec
37
+
38
+ - name: Push gem to RubyGems
39
+ run: gem push assistant-*.gem
40
+
41
+ - name: Create GitHub Release
42
+ if: startsWith(github.ref, 'refs/tags/')
43
+ uses: softprops/action-gh-release@v2
44
+ with:
45
+ generate_release_notes: true
46
+ files: assistant-*.gem
data/.gitignore CHANGED
@@ -4,10 +4,14 @@
4
4
  /coverage/
5
5
  /doc/
6
6
  /pkg/
7
+ /_site/
8
+ /.jekyll-cache/
9
+ /.jekyll-metadata
7
10
  /spec/reports/
8
11
  /tmp/
9
12
 
10
13
  # rspec failure tracking
11
14
  .rspec_status
12
15
  .byebug_history
13
- assistant-*.gem
16
+ assistant-*.gem
17
+ .vscode/
@@ -0,0 +1,6 @@
1
+ {
2
+ "default": true,
3
+ "MD013": false,
4
+ "MD024": { "siblings_only": true },
5
+ "MD043": false
6
+ }
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ package.json
3
+ package-lock.json
4
+ bun.lock
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "plugin": [
4
+ "@tarquinen/opencode-dcp@latest",
5
+ [
6
+ "@plannotator/opencode@latest",
7
+ {
8
+ "workflow": "plan-agent",
9
+ "planningAgents": ["plan"]
10
+ }
11
+ ]
12
+ ]
13
+ }
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: create-pr
3
+ description: Use when opening a GitHub pull request for the assistant gem (e.g. `gh pr create`, "open a PR", "ship this branch"). Ensures local checks pass, only intended files are committed, commit/PR follow the M<num> convention, and the PR is assigned to the GitHub user before returning the URL.
4
+ ---
5
+
6
+ # Skill: create-pr
7
+
8
+ PRs for this repo follow a strict shape. Walk through every step in order.
9
+ Skipping any one of them is a defect.
10
+
11
+ ## 1. Verify local checks before pushing
12
+
13
+ Run all three from the worktree root and confirm each is green. None of these
14
+ should be skipped because "the change is small" — the CI gate will reject the
15
+ PR anyway.
16
+
17
+ ```sh
18
+ bundle exec rake test
19
+ bundle exec rubocop
20
+ bundle exec steep check --jobs=1
21
+ ```
22
+
23
+ If anything fails, fix it on the branch (or revert the offending hunk) before
24
+ committing. Do not commit "WIP" or "fix in CI" placeholders.
25
+
26
+ ## 2. Stage only the intended files
27
+
28
+ Inspect `git status --short` before staging. Explicitly enumerate paths to
29
+ `git add` — never run `git add .` or `git add -A`.
30
+
31
+ **Always exclude** the following even if they appear as untracked or modified:
32
+
33
+ - Anything under `.opencode/` **except** committed config (`.opencode/.gitignore`,
34
+ `.opencode/opencode.json`) and project-owned skills under
35
+ `.opencode/skills/<name>/`. Transient agent state, scratch files, and
36
+ unrelated skills (e.g. `.opencode/skills/ruby-services/` if not owned by
37
+ this project) stay untracked.
38
+ - `.DS_Store`, `*.swp`, `*~`, any local-only debug scripts
39
+ - `Gemfile.lock` is fine to commit when an actual dep changed; do not stage it
40
+ for unrelated mechanical updates
41
+
42
+ If something unrelated was modified during exploration (e.g. accidental
43
+ reformat of an untouched file), restore it with `git restore <path>` first.
44
+
45
+ After staging, re-check with `git diff --cached --stat` and confirm the file
46
+ list matches the PR's scope.
47
+
48
+ ## 3. Commit message convention
49
+
50
+ The repo's commit messages follow:
51
+
52
+ ```
53
+ <TAG>: <short imperative summary, <=72 chars>
54
+
55
+ <wrapped body explaining the WHAT and WHY, not the HOW>
56
+ <reference roadmap milestones or issues by ID>
57
+ ```
58
+
59
+ `<TAG>` is one of:
60
+
61
+ - `M<n>` — a v1 roadmap milestone (e.g. `M11: bin/assistant-rbs per-class
62
+ RBS generator`). Look up the number in `docs/v1/02-features.md`.
63
+ - `M-S<n>` — a "stretch" / promoted roadmap item.
64
+ - `D<n>` — a documentation milestone from `docs/v1/04-documentation.md`.
65
+ - A short topic tag like `chore:`, `docs:`, `refactor:` when the change does
66
+ not map to a roadmap item.
67
+
68
+ The body wraps at ~72 cols and explains the WHY. Do not paste tool output or
69
+ file lists — the diff already shows that.
70
+
71
+ Pre-commit hooks may reject the commit. If they do, fix the issue and create
72
+ a **new** commit. Do not `--amend` past hook failures.
73
+
74
+ ## 4. Push and track
75
+
76
+ ```sh
77
+ git push -u origin <branch>
78
+ ```
79
+
80
+ The branch name should already match the work: `feature/m<n>-<slug>` for
81
+ roadmap milestones, or `<topic>/<slug>` otherwise.
82
+
83
+ ## 5. Open the PR
84
+
85
+ Use `gh pr create` with `--base main`, the explicit `--head <branch>`, a
86
+ `--title` that mirrors the lead commit's subject, and a `--body` that covers:
87
+
88
+ - **Scope** — what milestone / issue this implements (link the roadmap line).
89
+ - **What this PR ships** — bullet list of the public-facing changes.
90
+ - **Sample output / behavior** — fenced block when the change has a visible
91
+ surface (CLI output, generated artifact, error message).
92
+ - **Verification** — the green output of `rake test`, `rubocop`, and
93
+ `steep check`. Paste the actual tail of each command.
94
+ - **Out of scope** — what was deliberately left for later (e.g. "M12 changes
95
+ this DSL signature; that ships in its own PR").
96
+
97
+ Pass the body via a heredoc so newlines and quoting survive:
98
+
99
+ ```sh
100
+ gh pr create --base main --head <branch> --title "..." --body "$(cat <<'EOF'
101
+ ...
102
+ EOF
103
+ )"
104
+ ```
105
+
106
+ ## 6. Assign the PR
107
+
108
+ GitHub does not auto-assign. **Always** assign the PR to the authenticated
109
+ user immediately after creation:
110
+
111
+ ```sh
112
+ gh pr edit <number> --add-assignee "$(gh api user --jq .login)"
113
+ ```
114
+
115
+ Confirm the assignment landed by re-reading the PR URL output — `gh pr edit`
116
+ prints the URL on success.
117
+
118
+ ## 7. Return the PR URL
119
+
120
+ The final message to the user must include the PR URL on its own line so the
121
+ terminal renders it as a clickable link. Mention the PR number, the commit
122
+ SHA(s) it contains, and the assignee.
123
+
124
+ ## Common pitfalls
125
+
126
+ - **Committing transient `.opencode/` state** — agent scratch files and skills
127
+ that aren't owned by this repo must never appear in `git status` as staged.
128
+ Project-owned skills under `.opencode/skills/<name>/SKILL.md` are fine to
129
+ commit when they're part of the change.
130
+ - **Forgetting to push before `gh pr create`** — `gh` will error with
131
+ `pull request create failed: GraphQL: No commits between main and …`.
132
+ Always `git push -u origin <branch>` first.
133
+ - **Skipping the assignee step** — unassigned PRs get lost in the review
134
+ queue. Always run step 6.
135
+ - **Empty `--body`** — `gh pr create` will silently use the commit message as
136
+ the body, which usually under-documents the change. Always pass `--body`.
137
+ - **`--amend` after a pre-commit hook failure** — the failure already left
138
+ artifacts in the index; create a fresh commit instead.
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: ruby-services
3
+ description: Use when creating, changing, testing, or reviewing Ruby service objects, especially Assistant::Service subclasses, service inputs, validation, execution, logs, or Minitest coverage.
4
+ ---
5
+
6
+ # Ruby Services
7
+
8
+ Use this skill when working on Ruby service objects in this repository,
9
+ especially `Assistant::Service` subclasses or framework behavior that affects
10
+ service inputs, validation, execution, logs, result hashes, or tests.
11
+
12
+ Do not use this skill for unrelated Ruby scripts, packaging-only changes, or
13
+ opencode configuration tasks unless the work directly concerns Ruby service
14
+ guidance.
15
+
16
+ ## Core Approach
17
+
18
+ - Preserve the existing `Assistant::Service` public API unless the user asks for
19
+ an API change.
20
+ - Prefer soft-fail service behavior: report domain and validation failures with
21
+ error logs instead of raising, unless an exception is explicitly part of the
22
+ API being changed.
23
+ - Keep service logic clear and object-oriented: every method should have one
24
+ responsibility.
25
+ - Only add a private helper when it makes sense in the context of the service's
26
+ domain and improves readability.
27
+ - Keep helper names aligned with what the service does, not generic process
28
+ steps like `handle_data` or `process_stuff`.
29
+ - Do not add arguments to service instance methods other than `initialize`.
30
+ Service behavior should use declared inputs and instance state.
31
+ - Return computed data from `execute`; put pre-execution domain checks in
32
+ `validate`.
33
+ - Use `log_item_warning`, `log_item_error`, `log_item_info`, or
34
+ `add_log(level:, source:, detail:, message:)` consistently with existing
35
+ log patterns.
36
+
37
+ ## Inputs
38
+
39
+ - Declare service inputs with `input :name, type: SomeClass` and existing DSL
40
+ options such as `required:`, `optional:`, `default:`, `allow_nil:`, and `if:`.
41
+ - Prefer `default: -> { [] }` or `default: -> { {} }` for mutable defaults.
42
+ - Use `allow_nil: true` only when explicit `nil` is a valid service value.
43
+ - Do not depend on deprecated `valid_require_*?` names in new internal code;
44
+ use the canonical `valid_required_*?` names.
45
+
46
+ ## Tests
47
+
48
+ - Add or update Minitest coverage under `test/**/*_test.rb` for behavior
49
+ changes.
50
+ - Use anonymous `Class.new(Assistant::Service)` fixtures for framework-level
51
+ service behavior, matching the existing tests.
52
+ - Assert the service result hash shape, `status`, `warnings`, `errors`, logs,
53
+ and memoization when relevant.
54
+ - For input DSL changes, cover required, optional, default, type, conditional,
55
+ and `allow_nil` behavior as applicable.
56
+ - Use helpers from `test/test_helper.rb` for log-item construction or warning
57
+ capture instead of duplicating helper setup.
58
+
59
+ ## Style
60
+
61
+ - Ruby target is 3.4.
62
+ - Start Ruby files with `# frozen_string_literal: true`.
63
+ - Prefer concise Ruby that matches nearby code; endless methods are acceptable
64
+ where they are already used.
65
+ - Respect the repo's hybrid compact nesting convention from
66
+ `rubocop-style-compact_nesting`.
67
+ - Keep public API documentation aligned with `docs/v1/01-api-surface.md` and
68
+ user-facing changes aligned with `CHANGELOG.md` when appropriate.
69
+ - Make the smallest correct change; avoid generic abstractions until there is a
70
+ concrete second use.
71
+
72
+ ## Verification
73
+
74
+ Run the focused test first when possible, then the broader checks relevant to
75
+ the change:
76
+
77
+ ```sh
78
+ bundle exec ruby -Itest test/assistant/service_test.rb
79
+ bundle exec rake test
80
+ bundle exec rubocop
81
+ ```