ClaudeWrapper.Runner.Forcola (ClaudeWrapper v0.15.2)

Copy Markdown View Source

Leak-free runner backed by forcola.

Every claude invocation runs under forcola's Rust shim, which places the CLI in its own process group and kills the whole group (SIGTERM, then SIGKILL) on timeout, on early stream halt, or when the BEAM dies. That reaps claude and every stdio MCP server it spawned together, where the default ClaudeWrapper.Runner.Port would leave them running (see #185).

This module compiles only when forcola is a dependency. Select it with config :claude_wrapper, runner: ClaudeWrapper.Runner.Forcola. forcola is POSIX-only.

Requires forcola >= 0.4.0 and < 0.7.0. claude -p documents piped stdin as a supported input channel ("useful for pipes" in claude --help), and before 0.3.4 Forcola.run/2 and Forcola.Stream.lines/2 left the child's stdin open and unfed after spawn -- a child that reads it blocked until the timeout below instead of exiting normally (forcola#67). 0.3.4 closes the child's stdin right after spawn, so this module needs no stdin handling of its own.

Summary

Functions

Run to completion while observing stdout lines with a trusted callback.

Functions

run_observed(binary, args, opts, timeout, observer)

@spec run_observed(
  String.t(),
  [String.t()],
  keyword(),
  timeout() | nil,
  ClaudeWrapper.Runner.line_observer()
) ::
  {:ok, {String.t(), non_neg_integer(), String.t()}}
  | {:error, ClaudeWrapper.Runner.error()}

Run to completion while observing stdout lines with a trusted callback.

The timeout bounds the whole run, including a producer that keeps writing. Stderr is never merged into observed lines. See ClaudeWrapper.Runner for the callback and normalized output contract.