os-me: bump the stale decision-model pin and plug HeadlessClaude in as a provider #1488

Open
opened 2026-11-01 16:25:58 +00:00 by jared · 0 comments
Owner

os-me locks decision-model at an old commit. Four os-me files call decision-model classes or signatures that main deleted or changed. The next bundle update decision-model breaks os-me. Move os-me to the new runtime API, and register HeadlessClaude as a RubyLLM provider.

Blocked by: decision-model#21 (decision-model moves to the rebuilt llm-stack). Do with: cc-os #1502 (cc-os moves to the rebuilt llm-stack). Both change plugins/os-me.

What breaks

plugins/os-me/Gemfile.lock:3 pins revision: 3b7ae67 (decision-model 0.2.0, 2026-10-23). decision-model main is 57 commits ahead (count on 2026-11-01).

os-me call site decision-model API At 3b7ae67 On main
lib/os_me/headless_claude.rb:33 Wire::QuestionEncoder present deleted
lib/os_me/eval_adapter.rb:27 Adapters::CloudflareAccount present deleted (962bfe9; llm-stack owns credentials)
lib/os_me/eval_adapter.rb:16 CloudflareJev.build(account:) present signature is now build(credentials:, gateway_id: "n8n", timeout: 30)
lib/os_me/labeler_client.rb:6 Client.new(adapter, rules:) present replaced by Runtime.ask
lib/os_me/headless_claude.rb:26, test/headless_claude_test.rb:111 RawReply present legacy; deleted after email-triage#22
skills/decision-model/SKILL.md:26,43,76 CloudflareAccount, Answer documented stale

Before and after

Cloudflare credentials (settled)

# before: lib/os_me/eval_adapter.rb:16,27
Decision::Model::Adapters::CloudflareJev.build(account: account(env))
Decision::Model::Adapters::CloudflareAccount.new(account_id: account_id, api_token: api_token)

# after: decision-model main, lib/decision/model/adapters/cloudflare_jev.rb:9
Decision::Model::Adapters::CloudflareJev.build(credentials: { account_id:, api_token: })

The credential keys come from llm-stack README.md:104 (cloudflare | account_id, api_token). Confirm them against llm-stack lib/llm/providers/cloudflare/credentials.rb.

HeadlessClaude (target not settled)

Before: HeadlessClaude is a decision-model adapter. It returns a RawReply.

# lib/os_me/headless_claude.rb:22
def call(state:, questions:)
  request = HeadlessRequest.new(prompt: prompt(state, questions), cwd: Dir.tmpdir, model: @model,
                                schema: schema(questions))
  result = @runner.call(request)
  Decision::Model::RawReply.new(answers: result.answers, usage: result.usage,
                                model: "claude-#{@model || 'default'}")
end

# lib/os_me/labeler_client.rb:6
Decision::Model::Client.new(adapter, rules: Decision::Model::CriteriaRules::Off)

After: the target moves while two rebuilds run.

Source Registration form Status
decision-model docs/parity/runtime-library.md, migration row 105 LLM::Client.new(profile:, providers: { "headless_claude" => provider }); judge returns LLM::Decision goes away: the llm-stack rebuild deletes LLM::Client and LLM::Decision (#1502)
llm-stack branch rebuild/rubyllm-extension, lib/llm.rb; parity row P01 "drop" RubyLLM::Provider.register :claude_code, LLM::ClaudeCode::Provider (process-global) target; the form for a custom judge provider is not documented yet

Steps

  1. Wait for decision-model#21. Read its runtime API and the provider form it documents for a judge provider. Check if the llm-stack claude_code provider already does what HeadlessClaude does.
  2. Bump the decision-model lock to the ref that #21 ships. Coordinate the llm-stack pin with #1502.
  3. headless_claude.rb: turn it into a RubyLLM provider and register it as headless_claude. Replace Wire::QuestionEncoder with an encoding of the new questions hash.
  4. labeler_client.rb: call Runtime.ask through the registered provider.
  5. eval_adapter.rb: call CloudflareJev.build(credentials: { account_id:, api_token: }). Delete the CloudflareAccount wrapper.
  6. Update test/headless_claude_test.rb and skills/decision-model/SKILL.md.

Done when

  • The os-me suite passes on the new lock.
  • grep -rE 'Wire::|CloudflareAccount|RawReply|build\(account:' plugins/os-me returns nothing.

Constraints

  • HeadlessClaude stays in cc-os. decision-model ships no adapter for it (decision-model D-4; parity doc R6).
  • Some cc-os Gemfile.lock files have uncommitted edits. Do not stage, revert, or regenerate them for this work (same rule as #1502).

Origin: decision-model session 6e4cefcc-e24b-4704-9685-3e2349d11d2f.


Discoverer: /home/jared/dev/ruby-gems/decision-model, session 6e4cefcc-e24b-4704-9685-3e2349d11d2f, 2026-11-01. os-me pins a decision-model ref that uses classes decision-model deleted.

os-me locks decision-model at an old commit. Four os-me files call decision-model classes or signatures that main deleted or changed. The next `bundle update decision-model` breaks os-me. Move os-me to the new runtime API, and register `HeadlessClaude` as a RubyLLM provider. Blocked by: decision-model#21 (decision-model moves to the rebuilt llm-stack). Do with: cc-os #1502 (cc-os moves to the rebuilt llm-stack). Both change `plugins/os-me`. ## What breaks `plugins/os-me/Gemfile.lock:3` pins `revision: 3b7ae67` (decision-model 0.2.0, 2026-10-23). decision-model main is 57 commits ahead (count on 2026-11-01). | os-me call site | decision-model API | At 3b7ae67 | On main | | --- | --- | --- | --- | | `lib/os_me/headless_claude.rb:33` | `Wire::QuestionEncoder` | present | deleted | | `lib/os_me/eval_adapter.rb:27` | `Adapters::CloudflareAccount` | present | deleted (962bfe9; llm-stack owns credentials) | | `lib/os_me/eval_adapter.rb:16` | `CloudflareJev.build(account:)` | present | signature is now `build(credentials:, gateway_id: "n8n", timeout: 30)` | | `lib/os_me/labeler_client.rb:6` | `Client.new(adapter, rules:)` | present | replaced by `Runtime.ask` | | `lib/os_me/headless_claude.rb:26`, `test/headless_claude_test.rb:111` | `RawReply` | present | legacy; deleted after email-triage#22 | | `skills/decision-model/SKILL.md:26,43,76` | `CloudflareAccount`, `Answer` | documented | stale | ## Before and after ### Cloudflare credentials (settled) ```ruby # before: lib/os_me/eval_adapter.rb:16,27 Decision::Model::Adapters::CloudflareJev.build(account: account(env)) Decision::Model::Adapters::CloudflareAccount.new(account_id: account_id, api_token: api_token) # after: decision-model main, lib/decision/model/adapters/cloudflare_jev.rb:9 Decision::Model::Adapters::CloudflareJev.build(credentials: { account_id:, api_token: }) ``` The credential keys come from llm-stack `README.md:104` (`cloudflare | account_id, api_token`). Confirm them against llm-stack `lib/llm/providers/cloudflare/credentials.rb`. ### HeadlessClaude (target not settled) Before: `HeadlessClaude` is a decision-model adapter. It returns a `RawReply`. ```ruby # lib/os_me/headless_claude.rb:22 def call(state:, questions:) request = HeadlessRequest.new(prompt: prompt(state, questions), cwd: Dir.tmpdir, model: @model, schema: schema(questions)) result = @runner.call(request) Decision::Model::RawReply.new(answers: result.answers, usage: result.usage, model: "claude-#{@model || 'default'}") end # lib/os_me/labeler_client.rb:6 Decision::Model::Client.new(adapter, rules: Decision::Model::CriteriaRules::Off) ``` After: the target moves while two rebuilds run. | Source | Registration form | Status | | --- | --- | --- | | decision-model `docs/parity/runtime-library.md`, migration row 105 | `LLM::Client.new(profile:, providers: { "headless_claude" => provider })`; `judge` returns `LLM::Decision` | goes away: the llm-stack rebuild deletes `LLM::Client` and `LLM::Decision` (#1502) | | llm-stack branch `rebuild/rubyllm-extension`, `lib/llm.rb`; parity row P01 "drop" | `RubyLLM::Provider.register :claude_code, LLM::ClaudeCode::Provider` (process-global) | target; the form for a custom judge provider is not documented yet | ## Steps 1. Wait for decision-model#21. Read its runtime API and the provider form it documents for a judge provider. Check if the llm-stack `claude_code` provider already does what `HeadlessClaude` does. 2. Bump the decision-model lock to the ref that #21 ships. Coordinate the llm-stack pin with #1502. 3. `headless_claude.rb`: turn it into a RubyLLM provider and register it as `headless_claude`. Replace `Wire::QuestionEncoder` with an encoding of the new questions hash. 4. `labeler_client.rb`: call `Runtime.ask` through the registered provider. 5. `eval_adapter.rb`: call `CloudflareJev.build(credentials: { account_id:, api_token: })`. Delete the `CloudflareAccount` wrapper. 6. Update `test/headless_claude_test.rb` and `skills/decision-model/SKILL.md`. ## Done when - The os-me suite passes on the new lock. - `grep -rE 'Wire::|CloudflareAccount|RawReply|build\(account:' plugins/os-me` returns nothing. ## Constraints - `HeadlessClaude` stays in cc-os. decision-model ships no adapter for it (decision-model D-4; parity doc R6). - Some cc-os `Gemfile.lock` files have uncommitted edits. Do not stage, revert, or regenerate them for this work (same rule as #1502). Origin: decision-model session 6e4cefcc-e24b-4704-9685-3e2349d11d2f. -------- **Discoverer:** /home/jared/dev/ruby-gems/decision-model, session 6e4cefcc-e24b-4704-9685-3e2349d11d2f, 2026-11-01. os-me pins a decision-model ref that uses classes decision-model deleted.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#1488
No description provided.