README.md

<p align="center">
  <img src="assets/banner.png" alt="Crucible — Recursive LLM Code Execution for Elixir" width="700" />
</p>

<p align="center">
  <a href="https://hex.pm/packages/crucible"><img src="https://img.shields.io/hexpm/v/crucible.svg" alt="Hex.pm" /></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License" /></a>
</p>

---

> ⚠️ **Security Warning:** Crucible executes LLM-generated code via `Code.eval_string` with no sandbox. The model can access the full Elixir standard library, file system, network, and OS commands. **Do not run Crucible with untrusted input in production environments** without additional safeguards.

Crucible is a Recursive Language Model (RLM) execution engine for Elixir. It gives an LLM a stateful REPL — the model writes Elixir code, that code gets executed, the model sees the result, and the loop continues until the model arrives at a final answer.

## How it works

1. You provide a **question** (what to solve) and **input** (data to work with)
2. Crucible sends both to an LLM provider
3. The model writes Elixir code, which Crucible evaluates in a stateful REPL
4. Results feed back to the model for the next iteration
5. The loop continues until the model sets `final = "answer"` or hits the iteration limit

## Installation

### As a library

Add to your `mix.exs`:

```elixir
{:crucible, "~> 1.0"}
```

### Standalone binary (Burrito)

Crucible uses [Burrito](https://github.com/burrito-elixir/burrito) for standalone binaries:

```bash
git clone https://github.com/Whoaa512/crucible.git
cd crucible
mix deps.get
MIX_ENV=prod mix release crucible
```

Binaries are output to `burrito_out/` for your platform.

## CLI Usage

```bash
crucible run "Summarize the key points" --input data.txt --provider openai --model gpt-4o
crucible skills list                    # View cached skill snippets
crucible skills clear                   # Clear skill cache
crucible logs list                      # List trajectory logs
crucible logs cleanup --max-age 7       # Delete logs older than 7 days
crucible providers                      # List available providers
crucible version                        # Print version
crucible --help                         # Show usage
```

### Run options

| Option | Description |
|--------|-------------|
| `--input FILE` | **Required.** Input file (or `-` for stdin) |
| `--provider NAME` | LLM provider: `openai`, `anthropic`, `openrouter`, `codex` |
| `--model NAME` | Model name (provider-specific) |
| `--api-key KEY` | API key (or set via env: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.) |
| `--max-iterations N` | Maximum REPL loop iterations (default: 10) |
| `--temperature F` | Sampling temperature |
| `--max-tokens N` | Max tokens per response |
| `--skills` | Enable skill caching (retrieves similar past solutions) |
| `--skills-db PATH` | Custom SQLite path for skill cache |
| `--retry` | Enable retry with exponential backoff |
| `--no-log` | Disable trajectory logging |
| `--json` | Output result as JSON |
| `--quiet` | Suppress iteration progress output |

## Library Usage

```elixir
{:ok, answer, meta} = Crucible.completion(
  "What is the average of these numbers?",
  "4, 8, 15, 16, 23, 42",
  provider: :openai,
  model: "gpt-4o",
  return_meta: true
)
```

## Skill Caching

When `--skills` is enabled, Crucible stores successful (question, code) pairs in a SQLite database. On subsequent runs, it retrieves the top-3 most similar past solutions and injects them into the system prompt, helping the model solve similar problems faster.

## Providers

| Provider | Env Variable | Notes |
|----------|-------------|-------|
| OpenAI | `OPENAI_API_KEY` | GPT-4o, GPT-4, etc. |
| Anthropic | `ANTHROPIC_API_KEY` | Claude models |
| OpenRouter | `OPENROUTER_API_KEY` | Multi-provider gateway |
| Codex | `OPENAI_API_KEY` | Codex models |

## License

MIT