dagmar
This is dagmar's own Dagger module (seed cbb8 spike: engine tenancy & Run concurrency).It prototypes dagmar's Hybrid-C topology hermetically: an in-cluster Dagger engine
serving agent pods, brought up inside an isolated k3s cluster that itself runs inside
the OUTER Dagger engine (Docker Desktop). The outer engine runs this module; the inner
engine (deployed into k3s) is the system under test. Never touches the production
netcup cluster.
Installation
dagger install github.com/denkhaus/dagmar@741501a78e60ef9e16ec5199922447a4ecb41abbEntrypoint
Return Type
Dagmar !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| project | Directory | - | The target Project's source directory (per-Project binding seam). |
| seeds | String | - | seeds issue-store path for the Project (os-eco binding, per-Project). |
| mulch | String | - | mulch expertise-store path for the Project (os-eco binding, per-Project). |
| canopy | String | - | canopy prompt-store path for the Project (os-eco binding, per-Project). |
Example
dagger -m github.com/denkhaus/dagmar@741501a78e60ef9e16ec5199922447a4ecb41abb 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 🔗
Dagmar is dagmar’s main Dagger object (auto-named from the module). It is the primary entry point into dagmar’s Dagger functionality AND the per-Project binding seam: the New constructor binds the target Project + os-eco configuration once, and every method (Run, Sandbox, Gate, …) reuses that bound state (ADR-0010 §5).
deployEngine() 🔗
DeployEngine deploys the singleton Dagger engine as a privileged DaemonSet into k3s and reports the Ready engine pod. (cbb8 spike — the nesting test.)
Return Type
String !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| cluster | String | "dagmar-spike" | name of the throwaway k3s cluster |
Example
dagger -m github.com/denkhaus/dagmar@741501a78e60ef9e16ec5199922447a4ecb41abb call \
deploy-enginefunc (m *MyModule) Example(ctx context.Context) string {
return dag.
Dagmar().
Deployengine(ctx)
}@function
async def example() -> str:
return await (
dag.dagmar()
.deployengine()
)@func()
async example(): Promise<string> {
return dag
.dagmar()
.deployEngine()
}probe() 🔗
Probe validates Research Q3: can a Dagger CLIENT reach the singleton (nested) engine via
kube-pod://? Deploys the engine, then runs dagger core version in a client container
pointed at the inner engine through _EXPERIMENTAL_DAGGER_RUNNER_HOST=kube-pod://… A
version reported from the inner engine proves the singleton engine serves clients — the
precondition for multi-tenancy on one engine.
Return Type
String !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| cluster | String | "dagmar-spike" | name of the throwaway k3s cluster |
Example
dagger -m github.com/denkhaus/dagmar@741501a78e60ef9e16ec5199922447a4ecb41abb call \
probefunc (m *MyModule) Example(ctx context.Context) string {
return dag.
Dagmar().
Probe(ctx)
}@function
async def example() -> str:
return await (
dag.dagmar()
.probe()
)@func()
async example(): Promise<string> {
return dag
.dagmar()
.probe()
}probeCache() 🔗
ProbeCache is the dagmar-d8f0 spike: it empirically validates that a Dagger engine isolates
cache by volume NAME (the ADR-0008 §3 design assumption — “Dagger isolates cache by volume
name; cache poisoning across Projects is prevented as long as Projects use distinct
cache-volume names”). It is run as THREE separate dagger call probe-cache --mode ...
invocations — i.e. three separate client sessions against one engine, the cheapest faithful
analogue of “two client pods on the singleton engine”:
dagger call probe-cache --mode write # write MARKER_A into cache volume "…-A"
dagger call probe-cache --mode readsame # read volume "…-A" (expect MARKER_A → shares)
dagger call probe-cache --mode readdiff # read volume "…-B" (expect EMPTY → isolates)
If readsame sees the marker AND readdiff does not, name-based isolation is CONFIRMED (the ADR-0008 §3 claim holds locally); the remaining cross-Project concern is then purely the controller’s allocation of distinct names (a control-plane guarantee). LLM-free. (cbb8/d8f0-style spike; to be refactored into workflows/ later — ADR-0010 Consequences.)
Return Type
String !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| mode | String ! | - | which leg of the test to run: write | readsame | readdiff |
Example
dagger -m github.com/denkhaus/dagmar@741501a78e60ef9e16ec5199922447a4ecb41abb call \
probe-cache --mode stringfunc (m *MyModule) Example(ctx context.Context, mode string) string {
return dag.
Dagmar().
Probecache(ctx, mode)
}@function
async def example(mode: str) -> str:
return await (
dag.dagmar()
.probecache(mode)
)@func()
async example(mode: string): Promise<string> {
return dag
.dagmar()
.probeCache(mode)
}probeNet() 🔗
ProbeNet is the dagmar-911b trust-zone spike: it empirically tests whether a Dagger container exec has outbound network access by default. Dagger v0.21.8 exposes NO per-exec no-network option (ContainerWithExecOpts has no network/egress field). This establishes the residual-risk fact that ADR-0011 consciously accepts: tool-set exclusion is NOT a hard network guarantee (a raw exec path can still reach the network). LLM-free. (cbb8-style spike; to be refactored into workflows/ later — ADR-0010 Consequences.)
Return Type
String ! Example
dagger -m github.com/denkhaus/dagmar@741501a78e60ef9e16ec5199922447a4ecb41abb call \
probe-netfunc (m *MyModule) Example(ctx context.Context) string {
return dag.
Dagmar().
Probenet(ctx)
}@function
async def example() -> str:
return await (
dag.dagmar()
.probenet()
)@func()
async example(): Promise<string> {
return dag
.dagmar()
.probeNet()
}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
| Name | Type | Default Value | Description |
|---|---|---|---|
| image | String ! | - | Base OCI image for the Sandbox container. |
| workingDir | String | - | 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@741501a78e60ef9e16ec5199922447a4ecb41abb call \
sandbox --image stringfunc (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)
}up() 🔗
Up brings up an isolated k3s cluster inside Dagger and proves the API is reachable.
First checkpoint of the cbb8 spike: validates that k3s-in-Dagger works on this host (nested privileges / cgroup v2) before we deploy the Dagger engine DaemonSet into it.
Return Type
String !Arguments
| Name | Type | Default Value | Description |
|---|---|---|---|
| cluster | String | "dagmar-spike" | name of the throwaway k3s cluster |
Example
dagger -m github.com/denkhaus/dagmar@741501a78e60ef9e16ec5199922447a4ecb41abb call \
upfunc (m *MyModule) Example(ctx context.Context) string {
return dag.
Dagmar().
Up(ctx)
}@function
async def example() -> str:
return await (
dag.dagmar()
.up()
)@func()
async example(): Promise<string> {
return dag
.dagmar()
.up()
}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@741501a78e60ef9e16ec5199922447a4ecb41abb call \
sandbox --image string \
containerfunc (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()
}