Skip to content

Dagger#10

Open
andrewwhitecdw wants to merge 2 commits intoAgent-Field:mainfrom
andrewwhitecdw:dagger
Open

Dagger#10
andrewwhitecdw wants to merge 2 commits intoAgent-Field:mainfrom
andrewwhitecdw:dagger

Conversation

@andrewwhitecdw
Copy link
Contributor

Summary

  • What changed
  • Why it changed

Validation

  • [ x] make check
  • Relevant manual test performed (if needed)
    x

Behavior Impact

  • No behavior change
  • Backward compatible behavior change
  • Breaking change (explain below)

Notes

Any rollout notes, migration notes, or follow-ups.

- Add dagger_runner.py with run_dagger_pipeline, run_dagger_test, detect_project
- Support Python, Node, Rust, Go project detection
- Add CLI subcommand: swe-af dagger --pipeline lint|test|build|full
- Support services: postgres, redis, mysql, mongodb
- Add docs/DAGGER.md with usage documentation
- Update coder prompt with Dagger tool instructions
@AbirAbbas
Copy link
Collaborator

oooo this is very interesting, might sky-rocket the quality, will give it a review soon :)

@AbirAbbas AbirAbbas self-requested a review February 22, 2026 00:43
@andrewwhitecdw
Copy link
Contributor Author

andrewwhitecdw commented Feb 22, 2026

I may have pushed this branch prematurely, feel free to give this the most brutal feedback you can come up with for a better version :)

My main idea was to use dagger to improve SWE-AF's CICD itself by enabling ephemeral docker container builds of the project itself that will reduce CICD time 99% of the second run. I think the DAG implementation of Dagger matches perfectly with the DAG workflows of AgentField.

An additional idea is allowing Agents to use the dagger subsystem for testing their workflows in isolated containers and I am fairly sure that is not working in the PR and I don't yet understand how it would interface with AgentField, I still need to understand how it works but I should be able to figure it out by end of the week.

An alternative to container isolation I am interested in exploring is using a child project of dagger named container-use https://github.com/dagger/container-use which has better scaffolding for agentic container isolation.

Copy link
Collaborator

@AbirAbbas AbirAbbas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Dagger CI/CD Integration

Hey Andrew — really cool concept, the DAG alignment between Dagger and AgentField is spot on and this could be a massive win for agent self-validation. Leaving detailed inline comments below. The main blocker is the top-level import dagger which would break SWE-AF startup for every existing deployment that doesn't have dagger-io installed.

Summary of findings:

  • 1 blocker: Hard import dagger at module top level breaks startup without the dep
  • 2 bugs: timeout_seconds never wired up; run_pipeline_direct missing build/full branches (CLI advertises them)
  • Several improvements needed: service bindings only handle 2/4 services, poetry PATH glob, coder prompt references unusable API, code duplication between direct and reasoner paths

Happy to pair on any of these if useful!

import os
from enum import Enum

import dagger
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker: Top-level import dagger makes dagger-io a hard runtime dependency for all of SWE-AF. Since __init__.py unconditionally imports this module, any existing deployment without dagger-io installed will crash on startup with ModuleNotFoundError.

Suggestion: Lazy-import dagger inside the functions that need it, or guard with a try/except that sets a DAGGER_AVAILABLE flag:

try:
    import dagger
    DAGGER_AVAILABLE = True
except ImportError:
    DAGGER_AVAILABLE = False

Then check DAGGER_AVAILABLE at the start of each reasoner and return a clear error dict instead of crashing.


try:
async with dagger.Connection(
dagger.Config(timeout=120, execute_timeout=None)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: timeout_seconds is accepted as a parameter (default 600) but never used here. This line hardcodes timeout=120 and execute_timeout=None regardless of what the caller passes. Same issue at line 947 in run_pipeline_direct.

Suggestion:

async with dagger.Connection(
    dagger.Config(timeout=timeout_seconds, execute_timeout=timeout_seconds)
) as client:

)
container = container.with_env_variable(
"PATH",
"/root/.cache/pypoetry/virtualenvs/*/bin:/usr/local/bin:/usr/bin:/bin",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The literal * in PATH won't glob-expand when set as an env variable — it'll stay as the literal string */bin. Poetry commands in the container will fail because the virtualenv bin/ won't be on PATH.

Suggestion: Either use poetry run to prefix commands (e.g., poetry run pytest -v) which handles the virtualenv automatically, or resolve the actual venv path after poetry install:

container = container.with_exec(
    ["sh", "-c", "export PATH=$(poetry env info -p)/bin:$PATH"]
)

).with_exec(["pip", "install", "--quiet", "-e", ".[dev]"])

# Add services
for svc in services:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: This service binding loop only handles postgres and redis, silently ignoring mysql and mongodb even though get_service_container() (line 269) supports all four and the docs/schema advertise them.

Same issue in build_node_pipeline (line 404) and the lint fast-path (line 335).

Suggestion: Add elif branches for mysql and mongodb:

elif svc == DaggerService.MYSQL.value:
    container = container.with_service_binding("mysql", service_container.as_service())
    container = container.with_env_variable(
        "DATABASE_URL", "mysql://root:test@mysql:3306/test"
    )
elif svc == DaggerService.MONGODB.value:
    container = container.with_service_binding("mongodb", service_container.as_service())
    container = container.with_env_variable(
        "MONGO_URL", "mongodb://test:test@mongodb:27017"
    )

Or extract this into a shared helper to avoid repeating it 3 times.

lint_result = None
success = True

if pipeline_type == DaggerPipelineType.LINT:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: run_pipeline_direct only handles lint and test pipeline types, but the CLI (__main__.py) exposes --pipeline build and --pipeline full as valid choices. Running swe-af dagger --pipeline build will silently skip all pipeline logic, return success=True with no build executed, and report a misleading summary.

Suggestion: Either add build/full/custom branches here, or better yet, eliminate run_pipeline_direct entirely and have the CLI call run_dagger_pipeline directly (it already works without the AgentField server). That also eliminates the code duplication between these two ~100-line functions.

You have access to Dagger pipelines for isolated CI/CD validation. Use these
to verify your work in clean containers before committing:

**Available Dagger Tools (call via app.call):**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue: Coder agents are Claude Code subprocess instances — they have shell, file, and search tools but no Python app object. The app.call("run_dagger_pipeline", ...) examples here can't be used by the agents as written.

Suggestion: Reference the CLI instead, which agents can invoke via their Bash tool:

**Running Dagger from your tools:**
Use your Bash tool to invoke Dagger CLI:

```bash
# Run tests in isolated container
python -m swe_af dagger --pipeline test --path /path/to/worktree

# Full CI (build + test + lint)
python -m swe_af dagger --pipeline full --path /path/to/worktree

# With a database service
python -m swe_af dagger --pipeline test --services postgres --path /path/to/worktree

if result.get("lint_result"):
lr = result["lint_result"]
print(f"\nLint:")
print(f" Issues: {lr.get('total_issues', 0)}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: DaggerLintResult schema has no total_issues field — it has issues: list[dict]. This .get('total_issues', 0) always returns 0.

Suggestion: Use len(lr.get('issues', [])) instead.

@AbirAbbas
Copy link
Collaborator

Really like the direction here — giving agents isolated, reproducible environments for the testing they already do is a clear win.

One thing to flag: the pipeline builders currently only work for Python and Node (build_python_pipeline / build_node_pipeline). Rust, Go, Java, and Ruby are detected correctly by detect_project_type but fall back to build_python_pipeline, which means they'd try to run cargo test or go test ./... inside a python:3.12-slim container where those tools aren't installed.

Would be great to add build_rust_pipeline(), build_go_pipeline(), etc. with the right base images (golang:1.22, rust:1.77, etc.) — should be fairly straightforward since the structure is the same as the existing builders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants