Here Morgana takes life. Yours the shape, hers the spells — a functional interview with a domain expert, distilled into a complete, running Morgana domain
Alembic is Morgana's authoring workbench: an AI-conducted functional interview that distils a domain expert's own words into a complete Morgana domain — intents, agent prose, tool contracts, C# assets and non-regression scenarios — with no prompt ever written by hand. It is not a channel: it never calls a running Morgana, holds no JWT, joins no conversation pipeline — its only external dependency is an LLM. And it is not a filesystem tool: configuration arrives as an upload and leaves as a download, since at runtime Alembic can live anywhere — a cloud, an on-prem box beside Morgana, a laptop.
Alembic is itself an agent of Morgana: its own prompt is layered from an alembic.json of identical shape to a domain agent's (Target / Instructions / Personality / Formatting), composed with Morgana's own Personality resolved live from morgana.json — the same framework the domains it authors will run under.
C# owns the facts, the model owns the conducting. A domain-mapping pass turns the client's own words into intents, then five passes per agent build its prose incrementally, each reading back only what is already settled.
Every rule the framework enforces later and more expensively is checked here first, for free. The recap is the real composed prompt — framework layer and domain layer — not a summary of what was said.
One archive: a ready .csproj/.slnx, generated AgentX.g.cs sources split from a client-owned AgentX.cs half, a working LLM-authored mock per toolkit and an unconditional migration report.
A starter PromptHarness suite is derived from behavioural templates for the domain just authored, plus a cross-agent coherence pass that catches overlapping intents before the client leaves.
| Component | Role | Technology | Default Port |
|---|---|---|---|
| Distiller | The workbench itself — the interview, validation, emit | ASP.NET 10, Blazor Server | 5005 |
| LLM | Language model provider, Performance tier only | Anthropic, Azure OpenAI, Ollama, OpenAI | — |
| PromptHarness | Alembic's own non-regression suite — drives a scripted interview and asserts on what the interview conduct and finalization emit produce | xUnit v3, in-process | — |
Two doors, from the landing page: distil a brand-new domain, or continue one already in progress.
dotnet build and drop into a Morgana plugins/ folder.Nothing about an interview is lost to a closed tab past the last autosave interval: Save my work hands over a file at any point and the import page reads it back — by content, never by filename — to resume exactly where the client left off, mid-agent included.
A Morgana domain has two halves: the Intents a client's customers can ask for and one Agent per intent that answers it. The interview builds them in that order — intents first, since every agent maps to one — then walks the agent map five passes at a time, until each intent has its agent.
| Step | Runs | Settles |
|---|---|---|
| Domain Mapping | once | The whole Intents section: every name, description, label and opening sentence |
| Target | per entry | What the agent does, what it must never do |
| Personality | per entry | Which facet of Morgana this agent is |
| Toolkit | per entry | The tools, their descriptions, parameters, scopes and sharing |
| Instructions | per entry | Behavioural rules, written after the toolkit exists |
| Formatting | per entry | How the agent presents its own tools' output |
“Morganizing” a domain is Alembic's last step: once every intent has its agent, the reviewed domain downloads as one archive, because the pieces are only correct together — an agents.json whose toolkit has moved on from the C# beside it is a startup failure waiting to happen.
.csproj / .slnx, referencing Morgana.AI and Morgana.Contracts by PackageReference, pinned to the exact build Alembic itself runs againstagents.json, embedded as a resourceREADME.md (carrying the two-halves convention), MIGRATION.md and the interview's own save fileEach agent and toolkit is generated as two files, so a later re-run of Alembic never clobbers the client's own code: what is templated (deterministic, so a re-run produces no spurious diff) stays separate from what is authored by the LLM.
| File | Owner | Rule |
|---|---|---|
AgentX.g.cs | Alembic | Attributes, constructor, partial signatures — always overwritten |
AgentX.cs | The client | The working mock body, then the client's real integration — written once, never touched again |
A domain agent is its prose and prose gets edited — a client who leaves without scenarios has a domain nobody can revise safely. Alembic derives a starting PromptHarness suite from a library of behavioural templates, replacing every domain-word placeholder with this domain's own language.
| Template | Protects |
|---|---|
| capability-happy-path | The flow the agent exists for, end to end |
| prerequisite-before-action | It asks for what it needs instead of inventing it |
| confirmation-before-commit | Nothing irreversible happens before a yes |
| boundary-refusal | The edge its own Target commits it not to cross |
| tool-choice-under-ambiguity | A request between two tools reaches the right one |
| absent-subject | It says nothing was found instead of writing something plausible |
| withheld-detail | What its Formatting keeps back stays back |
| established-context-not-reasked | A value given once is not asked for twice |
Alembic/PromptHarness — distinct from the one shipped for Morgana — drives a scripted domain expert through a real interview and asserts on the mapping, the conduct across passes and the finalization emit, so the workbench stays honest as it evolves.
Alembic follows the same ASP.NET configuration hierarchy every unit in the repository does: appsettings.json → environment variables → User Secrets. It shares its UserSecretsId with Morgana.Web, so in-repo it runs against whatever LLM provider and tiers the working copy is already wired to — nothing to configure twice.
| Setting | Description |
|---|---|
| Morgana:LLM:Provider | LLM backend: Anthropic, AzureOpenAI, Ollama, OpenAI |
| Morgana:LLM:{Provider}:Tiers:Performance | The only tier Alembic declares — it never uses the Efficiency die. MagicDust carries both axes at zero: pricing is never read, since Alembic calls GetChatClient(Performance) directly rather than going through the metered agent adapter |
| Alembic:Work:AutosaveSeconds | How often the Draft in the circuit is snapshotted as a fallback for “Save my work” — never a resumption path on its own, only a floor under that one button (default: 30) |
Performance, it does not run against a single-tier deployment (Ollama being the canonical case) until a Performance entry is configured — the same “no cross-tier fallback” rule the framework itself enforces.
Alembic's Docker service is profile-gated, so an ordinary compose up skips it — it is an authoring-time tool, not part of the always-on runtime footprint.
| Resource | Location |
|---|---|
| Source code | github.com/mdesalvo/Morgana — Alembic/ |
| The workbench | Alembic/Distiller/, own Distiller.slnx |
| Alembic's own tests | Alembic/PromptHarness/, own PromptHarness.slnx |
| Local run | https://localhost:5005 — no running Morgana required |
| Design doctrine | Alembic/CLAUDE.md |
| Changelog | CHANGELOG.md in repository root |