Dagger
Search

dagmar

This is dagmar's Dagger module: the execution engine that runs the coder loop,
prompter loop, adjudicator loop, gate, and sandbox. The Kubernetes controller
dispatches these functions via `dagger call` from agent pods.

Installation

dagger install github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7

Entrypoint

Return Type
Dagmar !
Arguments
NameTypeDefault ValueDescription
projectDirectory -The target Project's source directory (per-Project binding seam).
Example
dagger -m github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7 call \
func (m *MyModule) Example() *dagger.Dagmar  {
	return dag.
			Dagmar()
}
@function
def example() -> dagger.Dagmar:
	return (
		dag.dagmar()
	)
@func()
example(): Dagmar {
	return dag
		.dagmar()
}

Types

Dagmar 🔗

entry point into dagmar’s Dagger functionality AND the per-Project binding seam: the New constructor binds the target Project once, and every method (Run, Sandbox, Gate, …) reuses that bound state (ADR-0010 §5). Project Hook Services (issues, memory, prompts) are exposed as native Dagger functions via WithMainModule(), not Go ports (ADR-0018).

adjudicate() 🔗

Adjudicate is dagmar’s adjudicator-loop entry point (ADR-0023 D4). When the deterministic Gate and the Reviewer-LLM disagree (gate green + reviewer veto, or gate redapprove), the Adjudicator resolves the conflict — it is the final automated decision maker before human escalation.

The Adjudicator is read-only: it reads source, issues, and memory to investigate the disagreement, but modifies nothing. It returns a structured verdict string naming one of three resolution paths: reviewer-wrong (calibrate reviewer, proceed), gate-wrong (coder repairs the gate checkables, full re-run), or escalate (unresolvable, human needed).

Unlike Prompt/Code, the Adjudicator does NOT use a chained prompter — its instructions come directly from the adjudicator meta-prompt (prompts.AdjudicatorMetaPrompt). The controller dispatches this via dagger call -m .dagger adjudicate --source <dir> .... Delegates to app.Adjudicate.

The args are primitives + Dagger types because Dagger codegen requires main-package types only. The app layer builds the read-only Env, sends the meta-prompt + disagreement context, and drives the Loop (ADR-0010 §3: Tier A direct).

Return Type
String !
Arguments
NameTypeDefault ValueDescription
sourceDirectory !-

source is the project source directory (read-only). The Adjudicator reads files from here to investigate the root cause of the disagreement.

gateResultString !-

gateResult is the gate’s outcome: “green” or “red” plus which checkables failed (if red) and their failure messages.

reviewResultString !-

reviewResult is the reviewer’s outcome: “approve” or “veto” plus the reviewer’s rationale.

taskContextString !-

taskContext is the original issue text / task description the coder was asked to implement.

modelString "anthropic/claude-sonnet-4"

model is the LLM model identifier (e.g. “anthropic/claude-sonnet-4”). The Adjudicator needs strong reasoning (ADR-0023 D6).

maxApicallsInteger 30

maxAPICalls bounds the LLM API calls for this adjudication Run. Higher than the prompter (adjudication may require deeper investigation of source

moduleRefString ".dagmar"

moduleRef is the project module reference (the Project CR’s moduleRef). Registers dagmar-issues + dagmar-memory as LLM-Tool hooks via WithMainModule. Defaults to “.dagmar” (dagmar dogfooding itself).

Example
dagger -m github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7 call \
 adjudicate --source DIR_PATH --gate-result string --review-result string --task-context string
func (m *MyModule) Example(ctx context.Context, source *dagger.Directory, gateResult string, reviewResult string, taskContext string) string  {
	return dag.
			Dagmar().
			Adjudicate(ctx, source, gateResult, reviewResult, taskContext)
}
@function
async def example(source: dagger.Directory, gateresult: str, reviewresult: str, taskcontext: str) -> str:
	return await (
		dag.dagmar()
		.adjudicate(source, gateresult, reviewresult, taskcontext)
	)
@func()
async example(source: Directory, gateResult: string, reviewResult: string, taskContext: string): Promise<string> {
	return dag
		.dagmar()
		.adjudicate(source, gateResult, reviewResult, taskContext)
}

code() 🔗

Code is dagmar’s coder-loop entry point (Phase 2 cognition, ADR-0021 D1). It constructs the Env, drives the LLM Loop, and returns the modified workspace Directory. The controller dispatches this via dagger call -m .dagger code --source <dir> --prompt-file <md>. Delegates to app.Code.

The args are primitives + Dagger types (Directory, File) because Dagger codegen requires main-package types only. The app layer builds the Env + LLM + Loop from these (ADR-0010 §3: Tier A direct). The prompt file is pre-composed by the controller (ADR-0005 merge).

Return Type
Directory !
Arguments
NameTypeDefault ValueDescription
sourceDirectory !-

source is the workspace Directory — the project source the agent works on (clone from ADR-0020 D1: dag.Git(repoURL).Branch(branchName).Tree()).

promptFileFile !-

promptFile is the resolved prompt .md (ADR-0005 cross-store merge, pre-computed by the controller). The agent receives this via WithPromptFile.

modelString "anthropic/claude-sonnet-4"

model is the LLM model identifier (e.g. “anthropic/claude-sonnet-4”).

maxApicallsInteger 100

maxAPICalls bounds the LLM API calls for this Run (token/cost cap, ADR-0021 D4). Engine-enforced hard stop: when exhausted, the Loop terminates.

moduleRefString ".dagmar"

moduleRef is the project module reference (the Project CR’s moduleRef). Defaults to “.dagmar” (dagmar dogfooding itself).

Example
dagger -m github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7 call \
 code --source DIR_PATH --prompt-file file:path
func (m *MyModule) Example(source *dagger.Directory, promptFile *dagger.File) *dagger.Directory  {
	return dag.
			Dagmar().
			Code(source, promptFile)
}
@function
def example(source: dagger.Directory, promptfile: dagger.File) -> dagger.Directory:
	return (
		dag.dagmar()
		.code(source, promptfile)
	)
@func()
example(source: Directory, promptFile: File): Directory {
	return dag
		.dagmar()
		.code(source, promptFile)
}

diff() 🔗

Diff computes the difference between a pre-Loop and post-Loop workspace (ADR-0021 D8). The controller calls this after Code() to extract the agent’s changes for the PR flow (ADR-0020 D3). Returns a Directory containing only the changed files.

Return Type
Directory !
Arguments
NameTypeDefault ValueDescription
afterDirectory !-

after is the post-Loop workspace (Code’s return value).

beforeDirectory !-

before is the pre-Loop workspace (the original clone).

Example
dagger -m github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7 call \
 diff --after DIR_PATH --before DIR_PATH
func (m *MyModule) Example(after *dagger.Directory, before *dagger.Directory) *dagger.Directory  {
	return dag.
			Dagmar().
			Diff(after, before)
}
@function
def example(after: dagger.Directory, before: dagger.Directory) -> dagger.Directory:
	return (
		dag.dagmar()
		.diff(after, before)
	)
@func()
example(after: Directory, before: Directory): Directory {
	return dag
		.dagmar()
		.diff(after, before)
}

prompt() 🔗

Prompt is dagmar’s prompter-loop entry point (ADR-0023 D1). It synthesizes a tailored prompt for the Coder or Reviewer by running a short LLM loop that reads project source, issues, and memory. The synthesized prompt is returned as a string — the controller forwards it as –prompt-file to the subsequent Code or Review Run.

The args are primitives + Dagger types because Dagger codegen requires main-package types only. The app layer builds the read-only Env, selects the meta-prompt by phase, and drives the Loop (ADR-0010 §3: Tier A direct). Delegates to app.Prompt.

Return Type
String !
Arguments
NameTypeDefault ValueDescription
sourceDirectory !-

source is the project source directory (read-only). The prompter reads files from here to ground the synthesized prompt in real project context.

phaseString !-

phase selects which meta-prompt to use: “pre-code” (coder) or “pre-review” (reviewer).

taskContextString !-

taskContext is the issue text / task description from the orchestrating Run.

modelString "anthropic/claude-sonnet-4"

model is the LLM model identifier (e.g. “anthropic/claude-sonnet-4”). The prompter may use a smaller/faster model — synthesis is well-bounded (ADR-0023 D6).

maxApicallsInteger 10

maxAPICalls bounds the LLM API calls for this synthesis Run. Low budget — prompt synthesis is well-bounded (ADR-0023 D1).

moduleRefString ".dagmar"

moduleRef is the project module reference (the Project CR’s moduleRef). Registers dagmar-issues + dagmar-memory as LLM-Tool hooks via WithMainModule. Defaults to “.dagmar” (dagmar dogfooding itself).

Example
dagger -m github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7 call \
 prompt --source DIR_PATH --phase string --task-context string
func (m *MyModule) Example(ctx context.Context, source *dagger.Directory, phase string, taskContext string) string  {
	return dag.
			Dagmar().
			Prompt(ctx, source, phase, taskContext)
}
@function
async def example(source: dagger.Directory, phase: str, taskcontext: str) -> str:
	return await (
		dag.dagmar()
		.prompt(source, phase, taskcontext)
	)
@func()
async example(source: Directory, phase: string, taskContext: string): Promise<string> {
	return dag
		.dagmar()
		.prompt(source, phase, taskContext)
}

sandbox() 🔗

Sandbox realizes an isolated, credentialed execution slot (a Dagger Container — Tier A, used directly; ADR-0010 §3). This is the v0 vertical proving the layout seams (functional core -> app Tier-A-direct -> main delegation -> a chainable custom return object) without an LLM call. Delegates to app.BuildSandbox.

NOTE: the args are primitives (not a domain.SandboxSpec) because Dagger cannot code-generate for a foreign (non-main-package) input type. The pure domain.SandboxSpec is constructed at this seam from the primitives; domain stays Dagger-free and unit-tested (ADR-0010 §3).

Return Type
Sandbox !
Arguments
NameTypeDefault ValueDescription
imageString !-

Base OCI image for the Sandbox container.

workingDirString -

Working directory inside the Sandbox (empty = image default). Named workingDir, not workdir, to avoid a CLI flag collision with *dagger.Container’s own workdir field.

Example
dagger -m github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7 call \
 sandbox --image string
func (m *MyModule) Example(image string) *dagger.DagmarSandbox  {
	return dag.
			Dagmar().
			Sandbox(image)
}
@function
def example(image: str) -> dagger.DagmarSandbox:
	return (
		dag.dagmar()
		.sandbox(image)
	)
@func()
example(image: string): DagmarSandbox {
	return dag
		.dagmar()
		.sandbox(image)
}

Sandbox 🔗

Sandbox is the Dagger object returned by Dagmar.Sandbox — a thin, chainable wrapper over the realized Container. Exported methods on it become callable Dagger functions.

container() 🔗

Container returns the underlying Dagger Container (Tier A).

Return Type
Container !
Example
dagger -m github.com/denkhaus/dagmar@90d9396b1899ed2fb867309898d03e690d744cb7 call \
 sandbox --image string \
 container
func (m *MyModule) Example(image string) *dagger.Container  {
	return dag.
			Dagmar().
			Sandbox(image).
			Container()
}
@function
def example(image: str) -> dagger.Container:
	return (
		dag.dagmar()
		.sandbox(image)
		.container()
	)
@func()
example(image: string): Container {
	return dag
		.dagmar()
		.sandbox(image)
		.container()
}