Configuration Discovery
Overview
The azdw tool uses a simple two-tier priority system for discovering configuration files. This ensures flexibility while maintaining a clear hierarchy for configuration precedence.
AI workspace assets add a project/workspace tier for azdw-owned AI sessions. Skills, prompt files, MCP configuration, and AGENTS.md have additional workspace discovery rules under .agents/, .github/, and .claude/. See Workspace Context and AI Discovery for those AI-specific paths. The general configuration rules below remain the reference for non-workspace configuration files.
Discovery Priority Order
Configuration files are discovered in the following priority order (highest to lowest):
- User Directory (
~/.azdw/config/)- Purpose: User-specific customizations and overrides
- Priority: Highest (always checked first)
- Typical Use: Production, personal configurations, custom settings
- Shipped Defaults (
{executable-directory}/config/)- Purpose: Factory default configurations shipped with the application
- Priority: Fallback (used only if user config doesn’t exist)
- Typical Use: Out-of-box experience, reference defaults
Read vs Write Behavior
Reading Configuration
When reading a configuration file:
- Check
~/.azdw/config/first (user overrides) - If not found, fall back to
{exe-dir}/config/(factory defaults) - If neither exists, use built-in defaults
Writing Configuration
All user modifications are always written to ~/.azdw/config/ (user directory).
This ensures:
- Factory defaults in
{exe-dir}/config/remain unchanged - User customizations are isolated and portable
- Clean separation between shipped defaults and user overrides
Visual Discovery Flow
┌─────────────────────────────────────────────────────────────┐
│ Configuration Request │
└─────────────────────┬───────────────────────────────────────┘
│
▼
┌────────────────────────────┐
│ 1. Check User Directory │
│ ~/.azdw/config/ │
└────────────┬───────────────┘
│
├─── Found? ──────► Use User Config ✓
│
▼ Not Found
┌────────────────────────────┐
│ 2. Check Shipped Defaults │
│ {exe-dir}/config/ │
└────────────┬───────────────┘
│
├─── Found? ──────► Use Factory Config ✓
│
▼ Not Found
┌────────────────────────────┐
│ Use Built-in Defaults │
│ (and create user config │
│ on first modification) │
└────────────────────────────┘
Configuration Types
1. Field Mappings
Purpose: Map Azure DevOps fields across different process templates (Agile, Scrum, CMMI) to unified logical field names.
Discovery Paths:
~/.azdw/config/field-mappings/{exe-dir}/config/field-mappings/
File Pattern: *.json, *.jsonc
Example Files:
bug-agile.jsoncuserstory-agile.jsoncepic-agile.jsonc
Command to View:
azdw config fieldmap list
Import Shipped Mapping to User Directory:
azdw config fieldmap import --source bug-agile.jsonc
2. Report Templates
Purpose: Scriban-based templates for rendering work item reports in various formats (Markdown, HTML, CSV).
Discovery Paths:
~/.azdw/templates/{exe-dir}/config/templates/
File Pattern: *.json
Example Files:
sprint-report-md.jsonepic-status-html.jsonbug-list-csv.json
Command to View:
azdw report template list
Import Shipped Template to User Directory:
azdw report template import --source sprint-report-md.json
3. Other Configuration Files
Discovery Paths:
~/.azdw/config/{exe-dir}/config/
Files:
relationship-policy.jsonc- Work item relationship validation rulesvisualization-config.jsonc- Graph visualization settingstool-categories.jsonc- AI chat tool category selectionmcp.jsonc- External MCP server configuration
4. Connection Configuration
Purpose: Azure DevOps organization connections and authentication credentials.
Location: ~/.azdw/connections.json (user directory only)
Command to Manage:
azdw connection list
azdw connection add
azdw connection test
5. Credentials
Purpose: Secure storage for PAT tokens and OAuth tokens.
Location: Platform-specific secure storage (Keychain on macOS, Credential Manager on Windows, Secret Service on Linux)
Command to Manage:
azdw credential store
azdw credential list
azdw credential remove
Platform-Specific Paths
macOS / Linux
| Priority | Path |
|---|---|
| User Directory | ~/.azdw/config/ |
| Shipped Defaults | {exe-dir}/config/ |
Example:
# User directory (overrides - checked first)
~/.azdw/config/field-mappings/bug-agile.jsonc
~/.azdw/config/tool-categories.jsonc
~/.azdw/templates/sprint-report-md.json
# Shipped defaults (factory defaults - fallback)
/usr/local/bin/azdw-osx-arm64/config/field-mappings/bug-agile.jsonc
/usr/local/bin/azdw-osx-arm64/config/templates/sprint-report-md.json
Windows
| Priority | Path |
|---|---|
| User Directory | %USERPROFILE%\.azdw\config\ |
| Shipped Defaults | {exe-dir}\config\ |
Example:
# User directory (overrides - checked first)
C:\Users\JohnDoe\.azdw\config\field-mappings\bug-agile.jsonc
C:\Users\JohnDoe\.azdw\config\tool-categories.jsonc
C:\Users\JohnDoe\.azdw\templates\sprint-report-md.json
# Shipped defaults (factory defaults - fallback)
C:\Program Files\azdw\win-x64\config\field-mappings\bug-agile.jsonc
C:\Program Files\azdw\win-x64\config\templates\sprint-report-md.json
Usage Scenarios
Scenario 1: Fresh Installation (Production)
Initial State: User installs azdw for the first time.
Discovery Behavior:
- User directory (
~/.azdw/) doesn’t exist - Shipped defaults found in
{exe-dir}/config/ - Tool uses shipped defaults automatically
- On first customization (import/create), user directory is created
Example:
# List templates (uses shipped defaults)
$ azdw report template list
Available templates:
- sprint-report-md (Shipped)
- epic-status-html (Shipped)
# Import to user directory for customization
$ azdw report template import --source sprint-report-md.json
Template imported to: ~/.azdw/templates/sprint-report-md.json
# Now user version takes precedence
$ azdw report template list
Available templates:
- sprint-report-md (User) ← Takes precedence
- sprint-report-md (Shipped)
- epic-status-html (Shipped)
Scenario 2: Development Mode
Initial State: Developer runs azdw from source code checkout.
Discovery Behavior:
- User directory (
~/.azdw/config/) checked first (may not exist in fresh dev environment) - Falls back to shipped defaults in output directory (
bin/Debug/config/) - After build, config files are copied to output directory
Example:
# Build project first to copy config to output
$ cd ~/Dev/azdw
$ dotnet build
# Run from output directory
$ bin/Debug/net10.0/azdw report template list
Available templates:
- sprint-report-md (Shipped) ← From output directory config/
- epic-status-html (Shipped)
# Create user override
$ azdw report template import --source sprint-report-md.json
Imported: ~/.azdw/templates/sprint-report-md.json
# Now user version takes precedence
$ bin/Debug/net10.0/azdw report template list
Available templates:
- sprint-report-md (User) ← Takes precedence
- epic-status-html (Shipped)
Scenario 3: Testing Custom Configurations
Initial State: User wants to test modifications without affecting production configs.
Strategy: Modify files in ~/.azdw/config/ (user directory). Factory defaults in {exe-dir}/config/ are never modified.
Example:
# Create user config to override factory defaults
$ mkdir -p ~/.azdw/config
$ cp /path/to/test-config.jsonc ~/.azdw/config/tool-categories.jsonc
# Test with user config
$ azdw ai-chat
# Uses ~/.azdw/config/tool-categories.jsonc
# Remove user config to revert to factory defaults
$ rm ~/.azdw/config/tool-categories.jsonc
$ azdw ai-chat
# Uses {exe-dir}/config/tool-categories.jsonc
Scenario 4: Multi-Platform Distribution
Initial State: Building self-contained packages for different platforms.
Discovery Behavior:
- Each platform folder (
dist/osx-arm64/,dist/linux-x64/,dist/win-x64/) is self-contained - Each contains its own
config/directory with shipped defaults - Executable can run from any location without installation
Package Structure:
dist/
├── osx-arm64/
│ ├── azdw ← Executable
│ ├── config/ ← Shipped defaults (self-contained)
│ │ ├── field-mappings/
│ │ └── templates/
│ └── plugins/
├── linux-x64/
│ ├── azdw
│ ├── config/ ← Shipped defaults (self-contained)
│ └── plugins/
└── win-x64/
├── azdw.exe
├── config/ ← Shipped defaults (self-contained)
└── plugins/
Usage:
# Run directly from platform folder
$ ./dist/osx-arm64/azdw report template list
Available templates:
- sprint-report-md (Shipped) ← From ./dist/osx-arm64/config/
# Or copy entire platform folder to installation directory
$ cp -r dist/osx-arm64 /usr/local/bin/azdw
$ /usr/local/bin/azdw/azdw report template list
Viewing Configuration Paths
Use the config paths command to see all discovered configuration paths:
$ azdw config paths
Configuration Paths:
====================
Field Mappings:
User: ~/.azdw/config/field-mappings/ (5 files)
Shipped: /usr/local/bin/azdw/config/field-mappings/ (8 files)
Templates:
User: ~/.azdw/templates/ (2 files)
Shipped: /usr/local/bin/azdw/config/templates/ (6 files)
Other Config:
User: ~/.azdw/config/ (3 files)
Shipped: /usr/local/bin/azdw/config/ (4 files)
Connections:
~/.azdw/connections.json (exists)
Priority Order:
1. User directory (highest - checked first)
2. Shipped defaults (fallback)
Importing and Exporting Configurations
Import Shipped Configuration to User Directory
Field Mappings:
# Import single mapping
$ azdw config fieldmap import --source bug-agile.jsonc
Imported: ~/.azdw/config/field-mappings/bug-agile.jsonc
# Import with merge strategy (combine with existing)
$ azdw config fieldmap import --source bug-agile.jsonc --merge
Merged into: ~/.azdw/config/field-mappings/bug-agile.jsonc
Report Templates:
# Import single template
$ azdw report template import --source sprint-report-md.json
Imported: ~/.azdw/templates/sprint-report-md.json
# Import from external file
$ azdw report template import --file /path/to/custom-template.json
Imported: ~/.azdw/templates/custom-template.json
Export Configuration to File
Field Mappings:
# Export user mapping
$ azdw config fieldmap export bug-agile.jsonc --output /backup/bug-agile.jsonc
Exported: /backup/bug-agile.jsonc
# Export shipped mapping
$ azdw config fieldmap export bug-agile.jsonc --source shipped --output /backup/bug-agile-shipped.jsonc
Exported: /backup/bug-agile-shipped.jsonc
Report Templates:
# Export user template
$ azdw report template export sprint-report-md.json --output /backup/sprint-report-md.json
Exported: /backup/sprint-report-md.json
Troubleshooting
Issue: Configuration Not Found
Symptoms: Tool reports “Configuration not found” or uses unexpected defaults.
Diagnosis:
# Check configuration paths
$ azdw config paths
# List available configurations
$ azdw config fieldmap list
$ azdw report template list
Solutions:
- Verify file exists: Check if configuration file exists in user or shipped directories
- Check file permissions: Ensure read permissions on configuration files
- Import shipped defaults: If user directory is empty, import shipped configurations
$ azdw config fieldmap import --source bug-agile.jsonc $ azdw report template import --source sprint-report-md.json - Rebuild executable: If shipped defaults missing, rebuild with proper config copy
$ dotnet publish src/azdw/azdw.csproj -c Release --self-contained -o publish/
Issue: Wrong Configuration Priority
Symptoms: User configuration not taking precedence over shipped defaults.
Diagnosis:
# Check which configuration is being used
$ azdw config fieldmap list --verbose
$ azdw report template list --verbose
Solutions:
- Verify user directory exists: Ensure
~/.azdw/config/or~/.azdw/templates/exists - Check file names match: User config must have same name as shipped config to override
- Import to correct location: Use import command to ensure proper user directory placement
$ azdw config fieldmap import --source bug-agile.jsonc
Issue: Multi-Platform Package Missing Config
Symptoms: Platform-specific executable in dist/{platform}/ can’t find shipped defaults.
Diagnosis:
# Check if config/ exists in platform folder
$ ls -la dist/osx-arm64/config/
# Verify config files present
$ ls -la dist/osx-arm64/config/field-mappings/
$ ls -la dist/osx-arm64/config/templates/
Solutions:
- Rebuild distribution package: Run
scripts/build-cli-all-platforms.ps1andscripts/create-dist-package.ps1 - Manually copy config: Copy config folder to each platform directory
$ cp -r config/ dist/osx-arm64/ $ cp -r config/ dist/linux-x64/ $ cp -r config/ dist/win-x64/ - Verify .csproj settings: Ensure
azdw.csprojincludes config copy directive:<ItemGroup> <Content Include="../../config/**/*"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup>
Issue: Permission Denied on User Directory
Symptoms: Can’t create or write to ~/.azdw/ directory.
Solutions:
- Check directory permissions:
$ ls -la ~/ $ chmod 755 ~/.azdw/ - Check parent directory permissions: Ensure home directory is accessible
- Check disk space: Verify sufficient disk space available
$ df -h ~
Best Practices
Development
- Use shipped defaults as reference: Don’t modify project root
config/for personal preferences - Test with user directory: Test customizations in
~/.azdw/to simulate production - Version control shipped defaults: Keep
config/in git for shipped defaults only - Build before testing: Run
dotnet buildto ensure shipped defaults copied to output
Production
- Import before customizing: Use
importcommand to copy shipped configs to user directory - Backup user configs: Export and backup customized configurations regularly
$ azdw config fieldmap export bug-agile.jsonc --output /backup/ $ azdw report template export sprint-report-md.json --output /backup/ - Document customizations: Add comments to explain custom configurations
- Test in isolation: Test configuration changes in separate user directory before production
Distribution
- Include config in all platforms: Ensure
config/copied to each platform folder in distribution packages - Document config discovery: Include this guide or link in distribution README
- Provide examples: Include example configurations in
config/directory - Version shipped defaults: Update version number or timestamp in shipped configs
Configuration File Format
All configuration files support JSON and JSONC (JSON with comments) formats.
Example Field Mapping (bug-agile.jsonc):
{
"workItemType": "Bug",
"processTemplate": "Agile",
"fields": {
// Logical name -> Azure DevOps field mapping
"title": "System.Title",
"state": "System.State",
"priority": "Microsoft.VSTS.Common.Priority",
"severity": "Microsoft.VSTS.Common.Severity"
}
}
Example Report Template (sprint-report-md.json):
{
"name": "sprint-report-md",
"description": "Sprint summary report in Markdown format",
"format": "markdown",
"template": "# Sprint \n\n..."
}