Alembic

Alembic

Here Morgana takes life. Yours the shape, hers the spells — a functional interview with a domain expert, distilled into a complete, running Morgana domain

HANDBOOK
.NET 10 Blazor Server Morgana.AI PromptHarness

Index

Architecture Overview

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.

🗺

The Interview

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.

Deterministic Validation & Recap

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.

📦

Turnkey Emit

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.

🧪

Non-Regression from Day One

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.

System Topology

ComponentRoleTechnologyDefault Port
DistillerThe workbench itself — the interview, validation, emitASP.NET 10, Blazor Server5005
LLMLanguage model provider, Performance tier onlyAnthropic, Azure OpenAI, Ollama, OpenAI
PromptHarnessAlembic's own non-regression suite — drives a scripted interview and asserts on what the interview conduct and finalization emit producexUnit v3, in-process
Performance tier, non-negotiable: Alembic's whole job is writing dispositive prose that does not contradict itself — exactly the task where a cheaper die amplifies contradiction-following failures. It runs once, at onboarding, not per conversational turn: this is the wrong place to save.

Getting Started

Two doors, from the landing page: distil a brand-new domain, or continue one already in progress.

A Fresh Domain

Continuing One

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.

The interviewee is not the agent's audience. The domain expert answering Alembic's questions will never talk to the agent themselves — their own customers will. So every piece of prose Alembic writes describes those customers to the agent; it is never addressed to the domain expert who supplied the answers.

The Interview

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.

StepRunsSettles
Domain MappingonceThe whole Intents section: every name, description, label and opening sentence
Targetper entryWhat the agent does, what it must never do
Personalityper entryWhich facet of Morgana this agent is
Toolkitper entryThe tools, their descriptions, parameters, scopes and sharing
Instructionsper entryBehavioural rules, written after the toolkit exists
Formattingper entryHow the agent presents its own tools' output
The map is a choice, not an inventory. The intents that make it into the domain are the ones that surface during the conversation with the domain expert — not necessarily every intent that characterizes their real-world business. What never comes up never makes the map.

Morganization

“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.

The File Split

Each 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.

FileOwnerRule
AgentX.g.csAlembicAttributes, constructor, partial signatures — always overwritten
AgentX.csThe clientThe working mock body, then the client's real integration — written once, never touched again

Prompt Harness: AI-driven Non-Regression Scenarios

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.

TemplateProtects
capability-happy-pathThe flow the agent exists for, end to end
prerequisite-before-actionIt asks for what it needs instead of inventing it
confirmation-before-commitNothing irreversible happens before a yes
boundary-refusalThe edge its own Target commits it not to cross
tool-choice-under-ambiguityA request between two tools reaches the right one
absent-subjectIt says nothing was found instead of writing something plausible
withheld-detailWhat its Formatting keeps back stays back
established-context-not-reaskedA value given once is not asked for twice
Alembic tests itself, too: a dedicated 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.

Configuration Reference

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.

SettingDescription
Morgana:LLM:ProviderLLM backend: Anthropic, AzureOpenAI, Ollama, OpenAI
Morgana:LLM:{Provider}:Tiers:PerformanceThe 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:AutosaveSecondsHow 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)
No single-tier deployment: because Alembic declares only 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.

Running Alembic

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.

# Run Alembic standalone docker compose --env-file .env --env-file .env.versions --profile authoring up alembic # Or from source cd Alembic/Distiller dotnet run # https://localhost:5005, no running Morgana required

Quick Reference

ResourceLocation
Source codegithub.com/mdesalvo/Morgana — Alembic/
The workbenchAlembic/Distiller/, own Distiller.slnx
Alembic's own testsAlembic/PromptHarness/, own PromptHarness.slnx
Local runhttps://localhost:5005 — no running Morgana required
Design doctrineAlembic/CLAUDE.md
ChangelogCHANGELOG.md in repository root