Get from a fresh clone to a running Cairnloop operator dashboard in a few minutes. This guide follows the example app at examples/cairnloop_example/ as its reference.

Prerequisites

  • Elixir 1.15+ / OTP 26+
  • Postgres 16+ with the pgvector extension installed

The pgvector extension powers Cairnloop's Knowledge Base embeddings. If you need a containerized Postgres with pgvector, the repository ships a docker-compose.yml at the repo root. From the repo root run:

docker compose up -d db

Install

Cairnloop ships an Igniter installer that adds the dependency and generates the database migration for you.

First, fetch deps:

mix deps.get

Then run the installer:

mix cairnloop.install

The installer does two things:

  1. Adds {:cairnloop, "~> 0.1.0"} to your mix.exs dependencies.
  2. Detects your Ecto repo via Igniter.Libs.Ecto.select_repo/1 and generates a create_cairnloop_tables migration that creates cairnloop_conversations and cairnloop_messages with the correct schema.

If no Ecto repo is found, the installer emits:

No Ecto repo found. Please create a migration manually for cairnloop tables.

In that case, create a priv/repo/migrations/<timestamp>_create_cairnloop_tables.exs migration by hand before running mix ecto.migrate.

Run migrations

After the installer has run, apply both your host app's migrations and the Cairnloop library's own migrations:

# Run host migrations (generated by the installer or written by hand)
mix ecto.migrate

# Run the Cairnloop library's own migrations
mix ecto.migrate --migrations-path deps/cairnloop/priv/repo/migrations

The library ships 15+ additional migrations (knowledge base, retrieval corpus, gap candidates, article suggestions, outbound, and more) that mix ecto.migrate alone will not apply. Skipping this second command will cause Postgrex.Error relation-not-found errors the first time any non-chat feature is exercised.

Tip: Add both commands to your ecto.setup alias in mix.exs so they always run together:

"ecto.setup": ["ecto.create", "ecto.migrate",
  "ecto.migrate --migrations-path deps/cairnloop/priv/repo/migrations",
  "run priv/repo/seeds.exs"]

Manual install (without Igniter)

If you prefer not to use Igniter, add Cairnloop to your deps directly:

# mix.exs
def deps do
  [
    {:cairnloop, "~> 0.1.0"}
  ]
end

Then create the create_cairnloop_tables migration manually.

Mount the Dashboard

Import the cairnloop_dashboard/2 macro and mount it under a scope in your router. The example app uses /support:

# lib/my_app_web/router.ex
import Cairnloop.Router, only: [cairnloop_dashboard: 2]

scope "/support", MyAppWeb do
  pipe_through :browser

  cairnloop_dashboard("/", session: %{"host_user_id" => "demo_operator"})
end

The cairnloop_dashboard/2 macro mounts routes under whatever path you pass as its first argument. With the /support scope above:

  • Inbox is at /support
  • A conversation is at /support/:id
  • Knowledge Base is at /support/knowledge-base
  • Settings is at /support/settings

This guide assumes /support as in the example app. Adjust paths to match your own scope if you mount elsewhere.

Route convention: Always use the path you pass to cairnloop_dashboard/2. The internal integration-test routes (not the shipped macro routes) will 404 for adopters.

Boot

The commands below are for the example app. Switch into it first, then set up the database and start the server:

cd examples/cairnloop_example
mix setup
mix phx.server

Then visit http://localhost:4000/support.

You should see the Cairnloop operator inbox. If you have the example app's seeded fixtures, 12–16 conversations across all lifecycle states are already there.

Next Steps

  • JTBD Walkthrough — walk the full Jobs-To-Be-Done lifecycle in the seeded example: inbox → conversation workspace → cmd+k search → AI draft approval → governed tool approval → resolve → outbound trigger → bulk recovery.
  • Host Integration — implement the four host behaviour contracts (ContextProvider, Notifier, AutomationPolicy, SLAPolicyProvider) so Cairnloop knows your app's context and policy.
  • Troubleshooting — resolve common install, migration, pgvector, and mount-config errors.