{"record":{"id":"b0ef0cb8239d00f7","repo":"can1357/oh-my-pi","slug":"tool-bridge-is-unavailable-in-this-kernel-b0ef0c","errorCode":null,"errorMessage":"tool bridge is unavailable in this kernel","messagePattern":"tool bridge is unavailable in this kernel","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/rb/prelude.rb","lineNumber":290,"sourceCode":"    __omp_emit_status(\"output\", \"count\" => combined.length, \"total_chars\" => combined.sum { |r| r[\"content\"].length })\n    combined\n  end\n\n  # -------------------------------------------------------------------------\n  # Host tool bridge (loopback HTTP) — `tool.<name>(args)`, completion, agent.\n  # -------------------------------------------------------------------------\n\n  module OmpBridge\n    INTENT_FIELD = \"i\"\n\n    module_function\n\n    def proxy_env\n      base = ENV[\"PI_TOOL_BRIDGE_URL\"]\n      token = ENV[\"PI_TOOL_BRIDGE_TOKEN\"]\n      session = ENV[\"PI_TOOL_BRIDGE_SESSION\"]\n      if base.nil? || base.empty? || token.nil? || token.empty? || session.nil? || session.empty?\n        raise \"tool bridge is unavailable in this kernel\"\n      end\n      [base.sub(%r{/+\\z}, \"\"), token, session]\n    end\n\n    def call(name, args)\n      require \"net/http\"\n      require \"uri\"\n      base, token, session = proxy_env\n      uri = URI(\"#{base}/v1/tool\")\n      payload = JSON.generate(\"session\" => session, \"run\" => $__omp_current_rid, \"name\" => name, \"args\" => args)\n      http = Net::HTTP.new(uri.hostname, uri.port)\n      http.open_timeout = 10\n      http.read_timeout = 7 * 24 * 3600\n      req = Net::HTTP::Post.new(uri)\n      req[\"Content-Type\"] = \"application/json\"\n      req[\"Authorization\"] = \"Bearer #{token}\"\n      req.body = payload\n      resp = http.request(req)","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/rb/prelude.rb#L272-L308","documentation":"The Ruby prelude's `OmpBridge` module forwards `tool.<name>(...)` calls to the host process over a loopback HTTP bridge. The bridge URL, bearer token, and session ID are injected via the PI_TOOL_BRIDGE_URL, PI_TOOL_BRIDGE_TOKEN, and PI_TOOL_BRIDGE_SESSION environment variables. `proxy_env` raises when any of the three is missing or empty, meaning the script is running without a live host bridge.","triggerScenarios":"Invoking any `OmpBridge.call` / `tool.<name>` helper (directly or via `call`) in a Ruby process where PI_TOOL_BRIDGE_URL, PI_TOOL_BRIDGE_TOKEN, or PI_TOOL_BRIDGE_SESSION is unset, nil, or an empty string — e.g. running the prelude outside an omp eval kernel or after the env was stripped (sudo, cron, sanitizing wrapper).","commonSituations":"Running a Ruby snippet standalone with `ruby script.rb` instead of inside the omp eval runtime; an env filter dropping PI_TOOL_BRIDGE_* variables; spawning a subprocess that does not inherit the kernel env.","solutions":["Run the script inside the omp eval kernel so the PI_TOOL_BRIDGE_* environment variables are injected.","Verify the variables exist before calling bridge functions: `abort 'no bridge' unless ENV['PI_TOOL_BRIDGE_URL']`.","If spawning subprocesses, forward ENV explicitly so the bridge vars propagate to the child.","If a tool call is genuinely not needed, guard the call behind a bridge-availability check and take a local fallback path."],"exampleFix":"// before\nresult = OmpBridge.call('read_file', { 'path' => 'x.txt' })  # env vars missing\n// after\nif ENV['PI_TOOL_BRIDGE_URL'] && ENV['PI_TOOL_BRIDGE_TOKEN'] && ENV['PI_TOOL_BRIDGE_SESSION']\n  result = OmpBridge.call('read_file', { 'path' => 'x.txt' })\nelse\n  result = File.read('x.txt') rescue nil\nend","handlingStrategy":"validation","validationCode":"BRIDGE_VARS = %w[PI_TOOL_BRIDGE_URL PI_TOOL_BRIDGE_TOKEN PI_TOOL_BRIDGE_SESSION]\nbridge_ready = BRIDGE_VARS.all? { |v| ENV[v] && !ENV[v].empty? }","typeGuard":null,"tryCatchPattern":"begin\n  value = OmpBridge.call(name, args)\nrescue RuntimeError => e\n  raise unless e.message == 'tool bridge is unavailable in this kernel'\n  value = local_fallback(name, args)\nend","preventionTips":["Always run bridge-dependent scripts inside the omp eval kernel, never via plain `ruby`.","Check all three PI_TOOL_BRIDGE_* variables at script start and fail fast with a clear message.","When spawning subprocesses, pass ENV through so bridge vars propagate."],"tags":["ruby","environment","missing-env-var","eval-prelude","tool-bridge"],"backgroundTag":"missing-env-var","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}