Skip to content

Generators & CLI

Protege ships Rails generators for everything you scaffold — the initial install, each extension type, and the self-hosted mail server — plus one rake task. This page is the reference for each.

protege:install

The one command that takes a host app from gem "protege" to a runnable dashboard.

bash
bin/rails g protege:install

It does the wiring it can do safely, and prints the rest as next steps. Specifically, it:

  • Installs the Rails frameworks Protege builds on — Active Storage (attachments) and Action Mailbox (inbound mail; this also creates app/mailboxes/application_mailbox.rb).
  • Writes config/initializers/protege.rb — a fully-documented initializer with ENV-backed defaults.
  • Mounts the engine at /protege, with a loud TODO to wrap the mount in your own authentication — the engine ships none.
  • Wires the Loop's recurring tick into config/recurring.yml (protege_responsibility_tick, every minute) for both production and development. Idempotent — a second run is a no-op.
  • Scaffolds a starter Agent persona so there's something to route mail to.

The steps it deliberately leaves to you — running migrations, wrapping the mount in auth, setting provider credentials, enabling eager_load in development — are printed at the end.

Extension generators

Four generators scaffold the extension surfaces. Each writes a correctly-shaped starter file into the configured path and applies the type suffix idempotently (see below).

protege:tool

bash
bin/rails g protege:tool lookup_order

Scaffolds a Protege::Tool subclass into config.tools_path (default app/tools). Tools are auto-discovered, so the new tool is live as soon as it loads — no wiring.

protege:resolver

bash
bin/rails g protege:resolver customer_context

Scaffolds a Protege::Resolver subclass into config.resolvers_path (default app/resolvers). Resolvers are not auto-discovered — add the new one to a persona's chain.

protege:hook

bash
bin/rails g protege:hook refund_audit

Scaffolds a Protege::Hook subclass into config.hooks_path (default app/hooks). Hooks are auto-discovered and wired to the event bus at boot.

protege:provider

bash
bin/rails g protege:provider scoop_llm

Scaffolds a Protege::Provider subclass into config.providers_path (default app/providers), with a protege_id derived from the name. Activate it by pointing config.provider_id at that id.

protege:persona

bash
bin/rails g protege:persona customer_service

Scaffolds a Protege::Persona subclass into config.personas_path (default app/personas). Remember the class is the rolecustomer_service becomes CustomerServicePersona — and the individual agent (Sundae) is a record you create from it. See Personas.

The type-suffix rule

The extension generators apply their type suffix idempotently, so you can name a generation however reads best and get the same result. All three of these produce class SendEmailTool in send_email_tool.rb:

bash
bin/rails g protege:tool send_email
bin/rails g protege:tool SendEmail
bin/rails g protege:tool SendEmailTool

The same holds for Resolver, Hook, Provider, and Persona suffixes.

protege:postfix

Scaffolds a self-hosted Postfix + OpenDKIM mail server you run yourself, for hosts that want no email provider in the loop.

bash
bin/rails g protege:postfix

It vendors the container build into deploy/mail/ (Dockerfile, Postfix/OpenDKIM/OpenDMARC config, the provisioning listener, and a full MAIL.md deploy guide), plus a Kamal accessory example and a GitHub Actions workflow to build the image. The files are copied verbatim — runtime values are substituted at container start. See Mail transport for the full deployment path.

rake protege:css:build

bash
bin/rails protege:css:build

Rebuilds the engine's compiled Tailwind CSS (app/assets/builds/protege.css) from the engine's views and helpers. It needs tailwindcss-rails in the host. You only need this if you're modifying the engine's own views — a normal host app never runs it.