Changed
-
OS Environment Variable Expansion: OS environment variables (e.g.,
$HOME,$PATH) are no longer expanded by Dagu for non-shell executor types (docker, http, ssh, jq, mail, s3, redis, etc.) and DAG-level configuration fields (ssh,smtp,s3,registry_auths). Only variables explicitly defined in the DAG scope (env:,params:,secrets:, step outputs) are expanded. OS variables pass through unchanged, letting the target environment (container, remote shell, etc.) resolve them. Shell command execution is unaffected. See RFC 007.To use a local OS variable in a config field, explicitly import it via the
env:block:env: - HOME_DIR: ${HOME} # Import OS $HOME into DAG scope ssh: user: deploy host: app.example.com key: ${HOME_DIR}/.ssh/deploy_key # Expanded — HOME_DIR is DAG-scoped
-
Auth by Default: The default authentication mode changed from
nonetobuiltin. New installations require creating an admin account via the/setuppage on first visit. The JWT token secret is auto-generated and persisted to{dataDir}/auth/token_secretif not explicitly configured. See RFC 018. -
DAG Type Validation: DAGs with
type: chain(the default) no longer allow thedependsfield on steps. Chain execution runs steps sequentially in definition order, making explicit dependencies redundant. To use thedependsfield for custom execution order, settype: graphexplicitly. This change prevents confusion between chain's implicit sequential ordering and graph's explicit dependency-based execution.
Removed
+- Legacy API: The old legacy API routes have been removed. All API access uses the current /api/v1 endpoints, which require authentication when builtin auth is enabled.
-
Static API Token (
auth.token): Theauth.token.valueconfiguration field andDAGU_AUTH_TOKENenvironment variable have been removed. Use API keys (builtin auth mode) or basic auth instead. API keys provide role-based access control and usage tracking. See API Keys for migration. -
Basic Auth Flat Fields: The top-level
is_basic_auth,basic_auth_username, andbasic_auth_passwordconfiguration fields have been removed. Useauth.mode: basicwithauth.basic.usernameandauth.basic.passwordinstead. The legacyDAGU_BASICAUTH_*environment variables have also been removed; useDAGU_AUTH_MODE=basic,DAGU_AUTH_BASIC_USERNAME, andDAGU_AUTH_BASIC_PASSWORD. -
Standalone OIDC Mode (
auth.mode: oidc): Removed. The valid auth modes are nownone,basic, andbuiltin. Use builtin + OIDC mode for SSO with user management and RBAC. See Builtin Authentication - OIDC/SSO. -
Admin Config (
auth.builtin.admin): Theauth.builtin.admin.username/auth.builtin.admin.passwordconfig fields andDAGU_AUTH_ADMIN_USERNAME/DAGU_AUTH_ADMIN_PASSWORDenvironment variables have been removed. The first admin account is now created via the/setuppage on first browser visit. -
Basic Auth
enabledField: Theauth.basic.enabledfield andDAGU_AUTH_BASIC_ENABLEDenvironment variable have been removed. Basic auth is activated by settingauth.mode: basic. -
Deprecated YAML Fields: The following deprecated fields have been removed from the YAML spec. Migrate to the replacement fields:
Removed Field Replacement Context runcallStep field for sub-DAG execution dirworking_dirStep field for working directory executortype+configStep field for executor configuration precondition(singular)preconditions(array)Both DAG-level and step-level container.workDircontainer.working_dirContainer working directory
Added
-
Access Log Configuration: New
access_log_modesetting controls HTTP request logging. Values:"all"(default — log all requests),"non-public"(skip public/static asset paths), or"none"(disable access logging). Environment variable:DAGU_ACCESS_LOG_MODE. -
Auth Mode Selection: Authentication mode is now configured via
auth.modefield. Valid modes:none,basic,builtin(default). Basic auth usesauth.mode: basicwithauth.basic.usernameandauth.basic.password. Environment variable:DAGU_AUTH_MODE. -
Coordinator Enabled Config: New
coordinator.enabledconfig option (default:true) andDAGU_COORDINATOR_ENABLEDenvironment variable to explicitly enable or disable the coordinator service. When disabled,start-allskips the coordinator and DAGs are never dispatched to workers. Acceptstrue/false/1/0. -
Self-Upgrade Command: New
dagu upgradecommand for in-place binary updates with SHA256 verification, backup support, and cross-platform compatibility. -
Literal Dollar Escape for Non-Shell Executors: Use
\$to emit a literal$in non-shell contexts (docker, http, ssh, jq, mail, etc.) and config fields. Shell-executed commands preserve native semantics. To emit a literal$$in non-shell contexts, escape both dollars:\$\$. -
Unified Execution Dispatch (
defaultExecutionMode): New server-leveldefaultExecutionModesetting controls whether DAGs run locally or are dispatched to workers. When set todistributed, all DAGs are automatically dispatched to the coordinator for worker execution, even without an explicitworker_selector. DAGs that must remain on the main instance can useworker_selector: localto override this behavior. -
Agent: AI assistant integrated into the Web UI for workflow management. The agent helps create, review, debug, and manage DAG workflows through an interactive chat interface. Supports multiple LLM providers (Anthropic, OpenAI, Google, OpenRouter, local models). Features include shell command execution with approval for dangerous operations, file reading/editing, DAG schema lookup, UI navigation, and web search.
-
Agent Delegate Tool: New
delegatetool for the agent that spawns up to 8 parallel sub-agents for independent sub-tasks. Each sub-agent runs in its own session with the same tools (minusdelegateto prevent recursion) and returns a summary to the parent. Sub-agent messages stream through the parent SSE connection. -
Trigger Type Visibility: DAG runs now display how they were initiated (scheduler, manual, webhook, subdag, retry). The trigger type is shown in the DAG runs list and detail views with distinct icons and labels. Available via the
triggerTypefield in the API response. -
CLI History Command: New
dagu historycommand displays execution history for DAG runs with comprehensive filtering (by date, status, tags, run ID), pagination (limit support up to 1000 results), and multiple output formats (table, JSON, CSV). -
LLM Model Fallback:
modelfield accepts array of model objects. First is primary, rest are fallbacks tried in order on any error. Per-model overrides fortemperature,max_tokens,top_p,base_url,api_key_name. -
Container Shell Wrapper: New
shellfield wraps step commands with a shell interpreter, enabling pipes, redirects, and command chaining without manual wrapping. Available in both image and exec modes.container: image: alpine:latest shell: ["/bin/sh", "-c"] steps: - command: cat file.txt | grep error | wc -l - command: npm install && npm test
-
Step Defaults (
defaults): New DAG-leveldefaultsfield that defines default values inherited by every step andhandler_onstep. Supports 8 fields:retry_policy,continue_on,repeat_policy,timeout_sec,mail_on_error,signal_on_stop,env,preconditions.defaults: retry_policy: limit: 3 interval_sec: 5 env: - LOG_LEVEL: info steps: - name: fetch-data command: curl https://api.example.com/data # Inherits retry_policy and LOG_LEVEL from defaults - name: custom-step command: ./run.sh retry_policy: limit: 1 interval_sec: 0 # Overrides retry_policy; still gets LOG_LEVEL from defaults
-
Major UI Redesign: Complete redesign of the user interface with improved dark mode support, modernized color palette, and streamlined navigation. Enhanced visual hierarchy across all pages including DAG lists, execution views, system status, and admin pages.
-
LLM Secret Masking: Secrets defined in the
secretsblock are now automatically masked before being sent to LLM providers in chat steps. This prevents accidental exposure of sensitive values to external AI APIs while still allowing secrets to be used in message content via${VAR}substitution. -
LLM Tool Calling: Chat executor now supports function calling / tool use, enabling AI agents to execute workflows as tools during sessions. Tools are defined as DAGs with automatic parameter discovery from
defaultParams.steps: - type: chat llm: provider: anthropic model: claude-sonnet-4-20250514 tools: - search_tool max_tool_iterations: 10 messages: - role: user content: "What's the latest news about AI?" --- name: search_tool description: "Search the web for information" defaultParams: "query max_results=10" steps: - command: echo "Searching for: $1" - command: curl "https://api.example.com/search?q=$1&limit=$2" output: SEARCH_RESULT
-
Tailscale Tunnel: Built-in remote access via embedded Tailscale node. Access Dagu from anywhere without port forwarding or VPN setup.
dagu server --tunnel
Modes:
--tunnel- HTTP on tailnet (WireGuard encrypted, no setup)--tunnel --tunnel-https- HTTPS on tailnet (requires HTTPS enabled in Tailscale admin)--tunnel --tunnel-funnel- Public internet access (requires Funnel enabled in Tailscale admin)
-
System Status Page: New admin-only page consolidating system health monitoring in one place. Includes scheduler service status, coordinator service status, worker status with health/pollers/running tasks, and resource usage charts (CPU, Memory, Disk, Load).
-
OIDC Integration for Builtin Auth (Recommended): Added OIDC/SSO login capability under builtin authentication mode. This is now the recommended way to use OIDC with Dagu, as it combines SSO convenience with full user management and RBAC. Key features: auto-signup on first login, role mapping from IdP groups, email domain filtering, email whitelist, customizable login button.
-
Synchronous Execution API: New endpoint
POST /api/v1/dags/{fileName}/start-syncthat executes a DAG and waits for completion before returning. Returns full execution details including all node statuses. Useful for automation scripts, CI/CD pipelines, and any scenario where you need to wait for a DAG to finish.curl -X POST "http://localhost:8080/api/v1/dags/my-dag/start-sync" \ -H "Content-Type: application/json" \ -d '{"timeout": 300, "params": "{}"}'
-
SFTP Executor: New step type for transferring files between local and remote servers via SFTP. Supports upload and download of files and directories, with atomic uploads using temporary files to prevent partial transfers.
ssh: user: deploy host: server.example.com steps: - name: upload-config type: sftp config: direction: upload source: /local/config.yaml destination: /remote/config.yaml
-
SSH Bastion Host Support: SSH executor now supports connecting through a jump/bastion host for accessing servers in private networks.
-
SSH Connection Timeout: Added
timeoutfield to SSH configuration (default: 30s) for controlling connection timeouts. -
S3 Executor: New step type for S3 operations with support for AWS S3 and S3-compatible services (MinIO, Google Cloud Storage, DigitalOcean Spaces, Backblaze B2). Operations: upload, download, list, delete. DAG-level connection defaults. Automatic multipart uploads for large files.
s3: region: us-east-1 access_key_id: ${AWS_ACCESS_KEY_ID} secret_access_key: ${AWS_SECRET_ACCESS_KEY} bucket: my-bucket steps: - name: upload-report type: s3 config: key: reports/daily.csv source: /tmp/report.csv command: upload
-
SQL Executor: New step types for database operations with PostgreSQL and SQLite support. Execute queries, import data from CSV/TSV/JSONL, and export results in multiple formats. Parameterized queries for SQL injection prevention. Transaction support with isolation levels.
steps: - name: query-users type: postgres config: dsn: "postgres://user:pass@localhost:5432/mydb" command: "SELECT * FROM users WHERE active = true" output: USERS
-
Redis Executor: New step type for Redis operations with support for all major Redis commands, pipelines, transactions, Lua scripts, and distributed locking. Connection modes: Standalone, Sentinel, Cluster. TLS support.
redis: host: localhost port: 6379 password: ${REDIS_PASSWORD} steps: - name: cache-lookup type: redis config: command: GET key: user:${USER_ID} output: CACHED_USER
-
PostgreSQL Connection Pool Management for Workers: Added global PostgreSQL connection pool configuration at the worker level to prevent connection exhaustion when multiple DAGs run concurrently in shared-nothing mode.
-
DAG Runs Tag Filter: Filter DAG runs by tags in the UI and API. Select multiple tags to filter runs from DAGs that have ALL specified tags (AND logic). Available via the new
tagsquery parameter on/api/v1/dag-runsendpoint (comma-separated). -
Key-Value Tags: Tags now support key-value pairs in addition to simple tags. Tag filtering supports four modes: exact key, exact key-value, negation, and wildcard patterns.
tags: env: prod team: platform
-
Tag Validation: Tags are validated at YAML load time. Keys must be 1-63 characters (alphanumeric,
-,_,.), values 0-255 characters (alphanumeric,-,_,.,/). -
Shared-Nothing Worker Architecture: Workers can now operate without shared filesystem access. Enables deployment in Kubernetes, multi-cloud, and containerized environments where NFS/shared volumes are not available. Static discovery, status pushing, log streaming, and zombie detection.
-
Web Terminal: Added optional web-based terminal for executing shell commands directly from the Dagu UI. Disabled by default for security. Enable via
DAGU_TERMINAL_ENABLED=true. -
Audit Logging Configuration: Added configuration option to enable/disable audit logging. Enabled by default. Configure via
DAGU_AUDIT_ENABLED=false. -
Git Sync: Synchronize DAG definitions with a Git repository.
-
Catchup (Missed Run Replay): New
catchup_windowfield enables automatic replay of missed cron runs when the scheduler restarts after downtime. Theoverlap_policyfield ("skip","all", or"latest") controls behavior when the DAG is still running during catchup. -
Unified Stop/Restart Scheduling: Stop and restart schedules are now evaluated by the same TickPlanner module that handles start schedules.
-
Remote Agent Tool: New
remotetool enabling task delegation to remote Dagu nodes. Agents can spawn and manage work across distributed instances with optional session ID support for idempotent session creation. -
Remote Node Management: Admin UI page for managing remote worker nodes with full CRUD operations and connection testing. REST API endpoints for remote node configuration.
-
Document Management: Comprehensive document management system with full CRUD and search capabilities. Dedicated Docs page with tree navigation and Markdown rendering for project documentation alongside DAG workflows.
-
Git-Sync Reconciliation: Enhanced Git-sync with forget, delete, and move operations for sync item management. Cleanup functionality to remove all missing items at once.
-
License Management: License validation, status tracking, and feature gating system for RBAC and audit logging.
-
Agent Personality (Soul): Agent personality management system with full CRUD capabilities. Users can select and customize agent personalities for chat sessions.
-
Agent API Cost Tracking: Per-message cost tracking for LLM API calls with USD pricing metadata. Enhanced agent step message persistence for cost analysis.
-
Provider-Native Web Search for Agent: Agents can use provider-native web search capabilities. Users can enable web search and configure maximum uses per request in agent settings.
-
Singleton Enqueue Option: New
singletonconstraint for the/dag-runs/enqueueendpoint ensures only one DAG with the same name can be running or queued at any time. (#1672)
Deprecated
-
DAG-level
max_active_runsfield: Themax_active_runsfield in DAG files is now deprecated for local (DAG-based) queues. Local queues now always use FIFO processing with concurrency of 1. For concurrency control, define global queues in~/.config/dagu/config.yamland assign DAGs using thequeuefield. -
max_active_runs: -1(queue bypass): Settingmax_active_runsto-1to bypass queueing is deprecated. All DAGs now go through the queue system with local queues defaulting to FIFO (concurrency 1).
Fixed
-
Sub-DAG Loading with Long Names: Fixed a bug where sub-DAG execution failed for DAG names near the 40-character limit.
-
Sub-DAG Spec View: Fixed "file not found" error when viewing the spec tab for sub-DAG runs in the UI.
-
Container Step Output Capture: Fixed an issue where
container.commandwas not executed when specified inside the container block without a top-levelcommandfield. -
Sub-DAG Error Masking in Parallel Execution: Fixed an issue where sub-DAG failures produced the cryptic error "no results available for node status determination" instead of the actual cause.
-
Windows Process Timeout and Subprocess Termination: Fixed
timeout_secnot being enforced on Windows. (#1635) -
Security: Path Traversal in DAG Creation API: DAG creation endpoint now validates names to prevent directory traversal attacks. (GHSA-6v48-fcq6-ff23, #1691)
-
Docker HOME Folder Substitution: Added
-Hflag tosudoinentrypoint.shso~correctly expands to/home/daguinstead of/rootinside Docker containers. (#1699) -
Cache Memory Bloat: Optimized cache implementation with more efficient eviction strategy to prevent excessive memory usage. (#1679)
-
Webhook Fallback Body: Webhooks now support arbitrary JSON payloads with intelligent format detection and automatic fallback handling. (#1668)
-
Queue Processing Stability: Enhanced queue processor stability with improved error handling and recovery mechanisms for DAG file operations during concurrent processing. (#1595)
-
Variable Expansion for Unknown Variables: Variable expansion now preserves unknown or undefined variables in their literal form instead of expanding to empty strings. (#1606)
-
Scheduler Queue Capacity on Retry: Retries for DAGs using global queues are now properly enqueued instead of executed immediately, respecting queue capacity limits. (#1676)
-
Working Directory Resolution: Enhanced working directory resolution to properly inherit from base configuration when not explicitly specified in DAG files. (#1641)
-
Upgrade Command Stability: Improved upgrade download reliability with retry logic and exponential backoff. Strengthened Windows binary replacement. (#1646)
-
Parallel + Call Parameter Splitting: Fixed expanded variable references being incorrectly split during parallel step execution with
call. (#1665) -
Environment Variable Expansion for Non-Unix Shells: Improved variable expansion handling for edge cases involving single quotes and adjacent characters on Windows PowerShell and cmd. (#1666)
-
Start Command Parameter Validation: Support for JSON-formatted parameters when executing DAG commands. Enhanced parameter validation for the
startCLI command. (#1663) -
Frontend Build Segfaults: Replaced TerserPlugin with esbuild for faster, more reliable frontend builds. (#1645)
-
Tag Sorting: Alphabetical sorting of tag filter combobox and DAG table tags list for better usability. (#1617)
-
Queue Count Display: Fixed queue status reporting to exclude currently running items from the queued count. (#1602)
Contributors
This release represents a massive effort with 108 merged pull requests since v1.30.3. We are deeply grateful to every contributor who helped make Dagu v2 a reality through code, bug reports, feature requests, reviews, and community support.
Special Thanks to @ghansham and @kriyanshii for providing many valuable feedback and ideas throughout the v2.0.0 development cycle. Their consistent engagement across issues, pull requests, and discussions has been instrumental in shaping this release.
Code Contributors
Contributors who authored merged pull requests for v2.0.0:
| Contributor | Contributions |
|---|---|
| @prods | Windows process timeout and subprocess tree termination fix (#1635), tag sorting and label ordering fix (#1617) |
| @kriyanshii | Production-ready Helm chart for Kubernetes deployment (#1613), scheduler queue capacity fix for retries (#1676) |
| @sahalbelam | Singleton option for enqueue API (#1672), filename-based DAG ingestion (#1630), queue count display fix (#1602) |
| @yonas | Replaced TerserPlugin with esbuild to fix frontend build segfaults (#1645) |
Bug Reporters
Contributors who identified and reported bugs that were fixed in v2.0.0:
| Contributor | Reports |
|---|---|
| @pdoronila | ${VAR} interpolation broken on Windows (#1661), -- separator required for params (#1660), parallel: + call: param splitting (#1658), base config workingDir inheritance (#1656), multiple dotenv files (#1657)
|
| @waterworthd-cim | False "cyclic plan detected" error with step ordering (#1618), maxActiveSteps has no effect (#1619)
|
| @insanity54 | LLM chat POST content-type set to text/plain (#1574), jq step outputs numbers in scientific notation (#1648)
|
| @sahalisro-blip | Node modules download error (#1561), queued DAG count incorrect (#1601) |
| @prods | timeoutSec not enforced on Windows (#1636)
|
| @simonmysun | Ambiguous HOME folder substitution in Docker (#1698) |
| @dendrite-soup | Security vulnerability report: unauthenticated RCE in default config (GHSA-6qr9-g2xw-cw92, #1700) |
| @dev-epices | Step name 29-character limit in parallel execution (#1631) |
| @sbartczak-aleno | No way to escape dollar sign ($) in non-shell contexts (#1628) |
| @Kirandeep-Singh-Khehra | workingDir not working with SSH executor (#1596)
|
| @abylon-io | Environment variables not expanded in mail settings (#1557) |
| @n3storm | Website docs menu entry pointing to old domain (#1644) |
| @aigeling | Documentation site unreachable (#1650) |
| @evanzhang87 | Live demo user not working (#1560) |
| @Evs91 | S3 Object Storage not recognized as valid type (#1690) |
| @scilo7 | Immediate execution does not respect workerSelector (#1638)
|
| @williamohara | Health endpoint access logging noise (#1694) |
Feature Requesters
Contributors who proposed features that were implemented in v2.0.0:
| Contributor | Requests |
|---|---|
| @ghansham | Key-value tags (#1495), queue capacity on retry (#1673), dynamic parameters (#1677), failed DAG queue behavior (#1674) |
| @kevinsimper | Trigger type visibility in DAG run history (#1610) |
| @bagemt | Container shell wrapper / generic entrypoint overwrite (#1589), interactive DAG graph library suggestion (#1593) |
| @sahalbelam | Singleton support for enqueue API (#1643), URL field for enqueue API (#1609) |
| @kriyanshii | Tag-wise search for DAG runs (#1494) |
| @NebulaCoding1029 | SFTP/FTP executor support (#1079) |
| @ByamB4 | Security features (#1687) |
| @Kaiden0001 | Log pagination improvements (#1579) |
| @thimuslux | Basic condition If/Then/Else (#1629) |
| @artemklevtsov | Helm chart for Kubernetes (#1492) |
| @berkaydedeoglu | Worker ID visibility (#1500) |
Community Support and Reviewers
Contributors who provided code reviews, helped diagnose bugs, answered questions, and supported the community throughout the v2.0.0 development cycle:
| Contributor | Support |
|---|---|
| @ghansham | Extensive code reviews, issue triage, and community support across 15+ issues and PRs including #1596, #1609, #1610, #1629, #1631, #1643, #1644, #1657, #1669, #1672, #1674, #1676, #1677. One of the most active community members. |
| @mkalinski93 | Distributed workers discussion and feedback (#1686) |
| @vnghia | Docker executor deprecation discussion (#1515) |
| @wilsoncd35 | logOutput sub-DAG inheritance report (#1555)
|
| @ben-auo | Containerd discussion (#1323) |
Historical Code Contributors
Contributors who authored code in previous releases that forms the foundation of v2.0.0:
@ArseniySavin,
@ddddddO,
@garunitule,
@Kiyo510,
@Lewiscowles1986,
@liooooo29,
@rafiramadhana,
@RamonEspinosa,
@rocwang,
@stefaan1o,
@x2ocoder,
@x4204,
@fishnux,
@triole,
@yarikoptic,
@zph,
@arky,
@Arvintian,
@jerry-yuan,
@jonnochoo,
@lvoeg,
@reneleonhardt,
@david-waterworth,
@Tagnard,
@thefishhat,
@AdityaTel89,
@Sarvesh-11,
@SiwonP,
@christinoleo
Community Participants
Everyone who participated in discussions, reported feedback, or helped other users during the v2.0.0 cycle:
@2012ZGZYY,
@accforgithubtest,
@admerzeau,
@agajic-modoolar,
@alangrafu,
@alext-extracellular,
@alfhj,
@alienscience,
@aptemus,
@AX-AMote,
@bellackn,
@bielids,
@biraj21,
@borestad,
@bremyozo,
@cernoel,
@chrishoage,
@CMiksche,
@codinggeeks06,
@Daffdi,
@DarkWiiPlayer,
@dat-adi,
@dAtBigFish,
@dev-a,
@dmitriy-b,
@don-philipe,
@eerison,
@erwan-airone,
@eugenechyrski,
@fbartels,
@frafra,
@georgeck,
@GhisF,
@gyger,
@hbina,
@helmut72,
@hgeritzer,
@HtcOrange,
@iainad,
@imkebe,
@jarnik,
@jeremydelattre59,
@jhuang732,
@JohnMatthiasWabwire,
@jonasban,
@jonathonc,
@jrisch,
@JuchangGit,
@jyroscoped,
@kacamific,
@kachida,
@kamandir,
@kylejbrk,
@lnlion,
@mdanilakis,
@Mice7R,
@mingjianliu,
@mitchplze,
@mnmercer,
@Netmisa,
@nicokant,
@nightly-brew,
@normal-coder,
@overflowy,
@Pangolin2097,
@peterbuga,
@piotrwalkusz1,
@plc-dev,
@pratio,
@rrottmann,
@saishreyakumar,
@samuelgodoy,
@sascha-andres,
@Sedymariama,
@semyon-t,
@SGRelic,
@SoarinFerret,
@tapir,
@tetedange13,
@tguructa,
@thibmart1,
@topjor,
@TrezOne,
@Vad1mo,
@vhespanha,
@volong113322-tech,
@wakatara,
@xinxinxinye,
@yangkghjh,
@ylaizet,
@yosefy,
@yurivish,
@ZivenLu,
@zobzn