Configuration Reference (asd.yaml)
Overview
The asd.yaml file at your project root is the single source of truth for how ASD manages your development environment. It contains four distinct areas:
| Section | Purpose | Documentation |
|---|---|---|
network: | Service definitions, tunnels, Caddy routing | This page + Caddy |
automation: | Task runner, background services, health checks | Automation |
hub: | Dashboard layout, widgets, themes | Dashboard |
features: | Auto-start flags, binary management, behavior toggles | This page |
Create it with:
asd init Or write one by hand. The only required fields are version and project.name.
Minimal Example
version: 1
project:
name: "my-app"
network:
services:
my-app:
dial: "127.0.0.1:3000"
host: "app.localhost"
paths: ["/"] This defines a single service running on port 3000, routable locally at http://app.localhost. That is enough to get started.
Project Settings
The project block identifies your project and configures global behavior:
project:
name: "my-project" # Required. Project identifier.
domain: "localhost" # Base domain for local service routing.
description: "My application" # Optional human-readable description.
plugins: [supabase] # List of enabled plugins.
project_root: "frontend" # Service ID that owns the root path "/".
package_manifests_dir: "apps" # Directory for monorepo package manifests. The name is used as a namespace for service IDs and appears in log output. The plugins array activates integrations like the Supabase plugin, which auto-discovers and registers Supabase services.
Section 1: Networking and Tunnels
The network: block defines your services and how they are reached locally and publicly.
Service Definitions
Each service maps a local address to routable URLs (local Caddy routes and optional public tunnel URLs):
network:
services:
frontend:
dial: "127.0.0.1:5173"
host: "app.localhost"
paths: ["/"]
public: true
subdomain: "frontend"
api:
dial: "127.0.0.1:8080"
paths: ["/api"]
stripPrefix: true
webhook-receiver:
dial: "127.0.0.1:9000"
public: true
subdomain: "webhook" All Service Properties
| Property | Type | Description |
|---|---|---|
dial | string | Local address and port to forward traffic to (e.g., 127.0.0.1:3000). This is the upstream your service listens on. Required for your own services. |
name | string | Optional display name for the TUI and logs. |
host | string | Hostname for host-based routing (e.g., app.localhost). |
paths | string[] | URL path prefixes for path-based routing (e.g., ["/api"]). |
stripPrefix | boolean | Remove the matched path prefix before forwarding to the upstream. |
public | boolean | Enable a public HTTPS tunnel for this service. |
subdomain | string | Subdomain prefix for the tunnel URL (e.g., myapp becomes myapp-<id>.eu1.tn.asd.engineer). |
publishPreferred | "host" or "path" or "both" | Which routing strategy to prefer for tunnel URLs. |
priority | number | Route ordering. Higher values match first. |
description | string | Human-readable description shown in the TUI. |
type | string | Service type label (added as X-ASD-Service-Type header). |
securityHeaders | object | Security header configuration. See Caddy. |
iframeOrigin | string or null | Origin allowed for iframe embedding. |
deleteResponseHeaders | string[] | Response headers to strip from the upstream. |
ingressTag | string or null | Per-service ingress identifier for monitoring. |
basic_auth | object | Per-service basic auth override. See Caddy. |
securitySensitive | boolean | Flag service as requiring authentication by default. |
env | object | Per-service environment variables (template-expanded). |
process | object | Auto-start process definition (cmd, cwd). |
Tunnel Configuration
Per-service tunnel settings:
network:
services:
api:
dial: "127.0.0.1:8080"
public: true # Create a public tunnel
subdomain: "api" # URL prefix
tunnelPort: 8080 # Override tunnel port (default: from dial)
tunnelProtocol: "http" # "http" or "tcp" Project-level tunnel defaults:
project:
tunnel:
preferred: false # Enable tunnels by default for all services
prefix: "app" # Default subdomain prefix
protocol: "http" # Default protocol Service IDs
Every service has a unique identifier — the key name in your YAML:
network:
services:
my-frontend: # service-id = "my-frontend"
dial: "127.0.0.1:3000"
api-server: # service-id = "api-server"
dial: "127.0.0.1:8080" Use service IDs in CLI commands:
asd net expose start my-frontend
asd net stop api-server
asd net open my-frontend Plugin services use namespaced IDs like supabase:studio and supabase:kong.
Network Inspection (Alpha)
The network inspector (asd inspect) is an alpha feature that uses mitmproxy for HTTP traffic debugging. A planned integration will add per-service inspection toggles directly in asd.yaml:
network:
services:
api:
dial: "127.0.0.1:8080"
inspect: true # Route traffic through mitmproxy (planned) When fully integrated, asd net will show an “Inspect Traffic” action per service, and Caddy will chain requests through the mitmproxy proxy transparently. Today, you configure your application to use localhost:8080 as its HTTP proxy manually.
Section 2: Caddy Configuration
The network.caddy block controls the local reverse proxy. See Caddy Reverse Proxy for the full reference.
network:
caddy:
enable: true
tls:
enabled: true
auto: true
basic_auth:
enabled: true
realm: "My Project"
routes: ["host", "path", "tunnel"] Caddy handles request routing, TLS termination, HTTP Basic Authentication, security headers, compression, and health check endpoints.
Section 3: Automation
The automation: block defines tasks you run with asd run <task>. See Automation for the full reference.
automation:
dev:
- run: "pnpm dev"
background: true
skipWhen:
port: 5173
- waitFor: "http://127.0.0.1:5173"
test:
- run: "pnpm test"
expect: "passed"
build:
- run: "pnpm build"
environment:
NODE_ENV: "production" When you run asd up without arguments, it looks for tasks named up, dev, or start in that order.
Section 4: Dashboard
The hub: block configures the widget-based dashboard layout. See Dashboard for the full reference.
hub:
globalSettings:
theme: "dark"
hideBoardControl: true
boards:
- name: "Development"
order: 1
views:
- name: "Services"
widgets:
- type: "service"
serviceId: "frontend"
columns: 4
rows: 4 Feature Flags
The features block toggles automatic behaviors:
features:
# Service discovery
auto_detect_services: true # Scan for running services on asd net apply
auto_onboard_detected: true # Automatically register discovered services
# Binary management
auto_install_binaries: true # Download Caddy, ttyd, etc. on asd init
skip_binaries: ["codeserver"] # Skip specific module binaries
# Auto-start (what starts on asd net apply)
auto_start_caddy: false # Start Caddy reverse proxy
auto_start_tunnel: false # Start tunnels for public services
auto_start_ttyd: false # Start web terminal
auto_start_codeserver: false # Start VS Code server
auto_start_mitmproxy: false # Start network inspector
auto_start_dbgate: false # Start database UI
# Security and networking
enable_restricted_ports: false # Allow binding to ports 1-1024 (requires setcap)
disable_authentication: false # Disable HTTP Basic Auth globally
show_auth_in_urls: true # Show credentials in displayed URLs
ingress_header: true # Add X-ASD-Ingress response header
# Dashboard
hub_visibility: "both" # "both", "public", "private", or false For most projects, the defaults work well. Enable auto_start_caddy and auto_start_tunnel if you want asd net apply to bring everything up in one command.
Plugins
Plugins extend ASD with network services from external tools.
Enabling Plugins
project:
name: "my-app"
plugins: [supabase] Available Plugins
| Plugin | Description | Services Provided |
|---|---|---|
supabase | Local Supabase development integration | supabase:studio, supabase:kong, supabase:mailpit |
Plugin Service Overlays
Plugin services appear automatically. Customize their routing without redefining the service:
network:
services:
supabase:studio:
paths: ["/studio"]
public: true
priority: 40 The difference between an overlay and a full service: overlays lack a dial property. They customize existing plugin services; full services define new ones.
Plugin Commands
asd plugin:supabase:bootstrap # Start Supabase + extract env vars to .env
asd plugin:supabase:start # Start Supabase services
asd plugin:supabase:stop # Stop Supabase services
asd plugin:supabase:extract # Extract env vars only Template Macros
Service definitions, plugin manifests, and automation steps support ${{ }} template expressions. These are expanded at configuration time before routes are applied.
Environment Variables
network:
services:
my-app:
dial: "127.0.0.1:${{ env.APP_PORT }}"
host: "${{ env.APP_HOST }}" Tunnel Credential Macros
These macros read from the credential registry. They work across all authentication types (SSH keys, tokens, ephemeral) and server types (shared, dedicated, self-hosted):
| Macro | Returns | Example Value |
|---|---|---|
${{ macro.tunnelHost("app") }} | Full tunnel hostname | app-fkmc.eu1.tn.asd.engineer |
${{ macro.tunnelClientId() }} | Short client ID | fkmc |
${{ macro.tunnelEndpoint() }} | Server FQDN | eu1.tn.asd.engineer |
${{ macro.exposedOrigin("app") }} | Full HTTPS origin | https://app-fkmc.eu1.tn.asd.engineer |
${{ macro.exposedOriginWithAuth("app") }} | Origin with credentials | https://user:pass@app-fkmc... |
When no tunnel credentials exist, these resolve to empty strings. Empty hosts are filtered out automatically.
Utility Macros
| Macro | Description |
|---|---|
${{ macro.getRandomPort() }} | Allocate a free port |
${{ macro.getRandomString(length=32) }} | Random alphanumeric string |
${{ macro.bcrypt(password="...", cost=12) }} | Generate a bcrypt hash |
${{ core.isDockerAvailable() }} | Returns true if Docker is running |
Network Package Manifests
For monorepo projects, ASD auto-discovers services from subdirectories using net.manifest.yaml files. Each package defines its own services, and ASD merges them into the network at discovery time.
my-monorepo/
asd.yaml # Root config with project settings
packages/
api/
net.manifest.yaml # API service definition
web/
net.manifest.yaml # Frontend service definition
admin/
net.manifest.yaml # Admin panel service definition Manifest Format
A net.manifest.yaml follows the same service schema as network.services in your root asd.yaml:
# packages/api/net.manifest.yaml
services:
api:
dial: "127.0.0.1:${{ env.API_PORT }}"
paths: ["/api"]
public: true
subdomain: "api"
description: "REST API server" Template macros work in manifests. Environment variables and tunnel credential macros are expanded at discovery time.
Configure the Manifest Directory
project:
name: "my-monorepo"
package_manifests_dir: "apps" # Look in apps/ instead of default packages/ Or set via environment variable: ASD_PACKAGE_MANIFESTS_DIR=services.
How Discovery Works
When you run asd net apply, ASD:
- Reads the root
asd.yaml - Scans
package_manifests_dirfor subdirectories containingnet.manifest.yaml - Expands template macros in each manifest
- Merges all discovered services into the network registry
- Generates Caddy routes for the combined service set
Services from manifests can be overridden by the root asd.yaml. If both define the same service ID, the root config wins.
Full Example
A comprehensive asd.yaml demonstrating all four sections:
version: 1
project:
name: "my-saas"
domain: "localhost"
plugins: [supabase]
package_manifests_dir: "apps"
features:
auto_detect_services: true
auto_install_binaries: true
auto_start_caddy: true
auto_start_tunnel: false
network:
caddy:
enable: true
basic_auth:
enabled: true
realm: "My SaaS Dev"
services:
frontend:
dial: "127.0.0.1:5173"
host: "app.localhost"
paths: ["/"]
public: true
subdomain: "app"
priority: 10
basic_auth:
enabled: false
api:
dial: "127.0.0.1:8080"
paths: ["/api"]
stripPrefix: true
public: true
subdomain: "api"
securityHeaders:
enableHsts: true
enableCompression: true
admin:
dial: "127.0.0.1:3001"
host: "admin.localhost"
basic_auth:
enabled: true
realm: "Admin Only"
supabase:studio:
paths: ["/studio"]
public: true
priority: 40
hub:
globalSettings:
theme: "dark"
boards:
- name: "Dev"
order: 1
views:
- name: "Services"
widgets:
- type: "service"
serviceId: "frontend"
columns: 4
rows: 4
automation:
dev:
- run: "pnpm dev"
background: true
skipWhen:
port: 5173
- waitFor: "http://localhost:5173"
build:
- run: "pnpm build && pnpm preview"
background: true Related Guides
- Caddy Reverse Proxy — routing, TLS, auth, security headers
- Automation — task runner, background processes, assertions
- Dashboard — fragment URLs, widget layout, Team module
- Getting Started — install ASD and create your first tunnel