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
pgvectorextension 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:
- Adds
{:cairnloop, "~> 0.1.0"}to yourmix.exsdependencies. - Detects your Ecto repo via
Igniter.Libs.Ecto.select_repo/1and generates acreate_cairnloop_tablesmigration that createscairnloop_conversationsandcairnloop_messageswith 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.setupalias inmix.exsso 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"}
]
endThen 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"})
endThe 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.