Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .claude/hooks/pre-commit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ fi

cd "$CLAUDE_PROJECT_DIR" || exit 0

# Skip checks if mix is not available (e.g., in CI or sandboxed environments)
if ! command -v mix &> /dev/null; then
exit 0
fi

echo "Running pre-commit checks..." >&2

if ! mix compile --warnings-as-errors 2>&1; then
Expand Down
1 change: 0 additions & 1 deletion .envrc

This file was deleted.

54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
test:
name: Elixir ${{ matrix.elixir }} / OTP ${{ matrix.otp }}
runs-on: ubuntu-latest
strategy:
matrix:
include:
- elixir: "1.19"
otp: "27"
env:
MIX_ENV: test
steps:
- name: Install system dependencies
run: sudo apt-get update -qq && sudo apt-get install -y -qq ripgrep

- uses: actions/checkout@v4

- uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}

- name: Cache deps
uses: actions/cache@v4
with:
path: |
deps
_build
key: ${{ runner.os }}-mix-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-mix-${{ matrix.elixir }}-${{ matrix.otp }}-

- name: Install dependencies
run: mix deps.get

- name: Compile (warnings as errors)
run: mix compile --warnings-as-errors

- name: Check formatting
run: mix format --check-formatted

- name: Run tests
run: mix test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ erl_crash.dump
# Environment files with secrets
.env
.env.*
.envrc

# macOS metadata
.DS_Store
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,25 @@ All notable changes to this project are documented here.
GitHub API via `curl` + `jq`, parses with `Jason`, and generates summaries via
parallel schema queries. Run with `mix rlm.examples web_fetch`.

- GitHub Actions CI workflow (compile, format, test)
- Security notice in README documenting the trust boundary

### Changed

- API key log output now shows only last 4 characters instead of first 12
- `.envrc` untracked and added to `.gitignore` (local direnv preference)
- Added `@moduledoc` to `RLMWeb.Endpoint`, `RLMWeb.Router`, `RLMWeb.RunListLive`,
`RLMWeb.RunDetailLive`, and `RLMWeb.Telemetry`
- Pre-commit hook skips gracefully when `mix` is not available

### Removed

- `demo_run.exs` — referenced missing `priv/foodlab.epub`; would crash on clone
- `RLMWeb.PageController`, `RLMWeb.PageHTML` — unused Phoenix generator leftovers
- `RLMWeb.channel/0` helper — no channels in the application
- Swoosh dependency and `RLMWeb.Mailer` — no email functionality exists
- `/dev/mailbox` route — removed with Swoosh

---

## [0.3.0] — 2026-02-24
Expand Down
7 changes: 3 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ rlm/
│ │ ├── router.ex
│ │ ├── telemetry.ex
│ │ ├── gettext.ex
│ │ ├── mailer.ex
│ │ ├── live/ # RunListLive (/), RunDetailLive (/runs/:run_id)
│ │ ├── components/ # CoreComponents, Layouts, TraceComponents
│ │ └── controllers/ # ErrorHTML, ErrorJSON, PageController, TraceDebugController
│ │ └── controllers/ # ErrorHTML, ErrorJSON, TraceDebugController
│ └── mix/tasks/ # mix rlm.smoke, mix rlm.examples
├── test/
│ ├── test_helper.exs
Expand Down Expand Up @@ -227,7 +226,7 @@ Read-only Phoenix LiveView dashboard. Serves on `http://localhost:4000`.
|---|---|
| `RLMWeb` | Phoenix web module (verified routes, component imports) |
| `RLMWeb.Endpoint` | Phoenix endpoint using `RLM.PubSub` as pubsub_server |
| `RLMWeb.Router` | Routes: `/` (RunListLive), `/runs/:run_id` (RunDetailLive), `/dev/dashboard`, `/dev/mailbox` |
| `RLMWeb.Router` | Routes: `/` (RunListLive), `/runs/:run_id` (RunDetailLive), `/dev/dashboard` |
| `RLMWeb.RunListLive` | `/` — list of all runs (from TraceStore + live PubSub updates) |
| `RLMWeb.RunDetailLive` | `/runs/:run_id` — recursive span tree with expandable iterations |
| `RLMWeb.TraceComponents` | HEEx components: `span_node/1`, `iteration_card/1` |
Expand All @@ -236,7 +235,7 @@ Read-only Phoenix LiveView dashboard. Serves on `http://localhost:4000`.
| `RLMWeb.CoreComponents` | Core UI components (flash, button, input, table, icon, etc.) |
| `RLMWeb.Layouts` | App layout, flash group, theme toggle |
| `RLMWeb.Gettext` | Internationalization backend |
| `RLMWeb.Mailer` | Swoosh mailer |


## Config Fields

Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,16 @@ Tools live inside the sandbox — the eval'd code calls `read_file/1`, `bash/1`,

---

## Security

RLM executes LLM-generated Elixir code via `Code.eval_string` with full access to the
host filesystem, network, and shell. **Do not expose RLM to untrusted users or untrusted
LLM providers.** It is designed for local development, trusted API backends (Anthropic),
and controlled environments. There is no sandboxing beyond process-level isolation and
configurable timeouts.

---

## Further reading

For a comprehensive architecture reference — OTP supervision tree, async-eval pattern,
Expand Down
9 changes: 0 additions & 9 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,6 @@ config :rlm, RLMWeb.Endpoint,
pubsub_server: RLM.PubSub,
live_view: [signing_salt: "G4RzK1j2"]

# Configure the mailer
#
# By default it uses the "Local" adapter which stores the emails
# locally. You can see the emails in your browser, at "/dev/mailbox".
#
# For production it's recommended to configure a different adapter
# at the `config/runtime.exs`.
config :rlm, RLMWeb.Mailer, adapter: Swoosh.Adapters.Local

# Configure esbuild (the version is required)
config :esbuild,
version: "0.25.4",
Expand Down
5 changes: 1 addition & 4 deletions config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ config :rlm, RLMWeb.Endpoint,
]
]

# Enable dev routes for dashboard and mailbox
# Enable dev routes for dashboard
config :rlm, dev_routes: true

# Do not include metadata nor timestamps in development logs
Expand All @@ -77,6 +77,3 @@ config :phoenix_live_view,
debug_attributes: true,
# Enable helpful, but potentially expensive runtime checks
enable_expensive_runtime_checks: true

# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false
6 changes: 0 additions & 6 deletions config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ config :rlm, RLMWeb.Endpoint,
hosts: ["localhost", "127.0.0.1"]
]

# Configure Swoosh API Client
config :swoosh, api_client: Swoosh.ApiClient.Req

# Disable Swoosh Local Memory Storage
config :swoosh, local: false

# Do not print debug messages in production
config :logger, level: :info

Expand Down
18 changes: 0 additions & 18 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,4 @@ if config_env() == :prod do
# force_ssl: [hsts: true]
#
# Check `Plug.SSL` for all available options in `force_ssl`.

# ## Configuring the mailer
#
# In production you need to configure the mailer to use a different adapter.
# Here is an example configuration for Mailgun:
#
# config :rlm, RLMWeb.Mailer,
# adapter: Swoosh.Adapters.Mailgun,
# api_key: System.get_env("MAILGUN_API_KEY"),
# domain: System.get_env("MAILGUN_DOMAIN")
#
# Most non-SMTP adapters require an API client. Swoosh supports Req, Hackney,
# and Finch out-of-the-box. This configuration is typically done at
# compile-time in your config/prod.exs:
#
# config :swoosh, :api_client, Swoosh.ApiClient.Req
#
# See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details.
end
6 changes: 0 additions & 6 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ config :rlm, RLMWeb.Endpoint,
secret_key_base: "wGMmiWW+w1iw84uJuC13MGBtRyTSECbvCuOgLhxi2fgyC3qgc/n+iJQXmqYAdAMo",
server: false

# In test we don't send emails
config :rlm, RLMWeb.Mailer, adapter: Swoosh.Adapters.Test

# Disable swoosh api client as it is only required for production adapters
config :swoosh, :api_client, false

# Print only warnings and errors during test
config :logger, level: :warning

Expand Down
52 changes: 0 additions & 52 deletions demo_run.exs

This file was deleted.

2 changes: 1 addition & 1 deletion examples/smoke_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ defmodule RLM.SmokeTest do
key ->
IO.puts("\nRLM Smoke Test")
IO.puts("==============")
IO.puts("API key: #{String.slice(key, 0, 12)}...")
IO.puts("API key: ...#{String.slice(key, -4, 4)}")
IO.puts("")
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/mix/tasks/rlm.examples.ex
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ defmodule Mix.Tasks.Rlm.Examples do
System.halt(1)

key ->
IO.puts(" API key: #{String.slice(key, 0, 12)}...")
IO.puts(" API key: ...#{String.slice(key, -4, 4)}")
end
end

Expand Down
8 changes: 1 addition & 7 deletions lib/rlm_web.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule RLMWeb do
@moduledoc """
The entrypoint for defining your web interface, such
as controllers, components, channels, and so on.
as controllers, components, and so on.

This can be used in your application as:

Expand Down Expand Up @@ -34,12 +34,6 @@ defmodule RLMWeb do
end
end

def channel do
quote do
use Phoenix.Channel
end
end

def controller do
quote do
use Phoenix.Controller, formats: [:html, :json]
Expand Down
7 changes: 0 additions & 7 deletions lib/rlm_web/controllers/page_controller.ex

This file was deleted.

10 changes: 0 additions & 10 deletions lib/rlm_web/controllers/page_html.ex

This file was deleted.

Loading