Auto-Discovery Tutorial#

This tutorial explains how scafctl automatically discovers solution files, making the -f flag optional for most commands.

Prerequisites#

  • scafctl installed and available in your PATH
  • Basic familiarity with YAML syntax and solution files
  • Completion of the Getting Started tutorial

Table of Contents#

  1. Overview
  2. How Auto-Discovery Works
  3. Search Order
  4. Supported Commands
  5. Examples
  6. Interaction with --cwd
  7. When Auto-Discovery Fails
  8. Best Practices

Overview#

Many scafctl commands accept a -f / --file flag to specify the solution file path. When this flag is omitted, scafctl searches the current directory (or the --cwd target) for a solution file using a well-defined search order.

This means you can simply cd into a project directory and run commands without specifying the file:

# Instead of:
scafctl run solution -f solution.yaml

# Just run:
scafctl run solution
# Instead of:
scafctl run solution -f solution.yaml

# Just run:
scafctl run solution

How Auto-Discovery Works#

When no -f flag is provided, scafctl searches for solution files using the unified resolution chain, which iterates over a set of folder prefixes and file names in order, returning the first match.

Search Order#

The search combines these folder prefixes with these file names:

Folder prefixes (checked in order):

  1. scafctl/ – conventional project subfolder
  2. .scafctl/ – hidden project subfolder
  3. (current directory) – no subfolder prefix

File names (checked in order for each folder):

  1. solution.yaml
  2. solution.yml
  3. scafctl.yaml
  4. scafctl.yml
  5. solution.json
  6. scafctl.json
  7. taskfile.yaml
  8. taskfile.yml
  9. actions.yaml
  10. actions.yml

This produces 30 candidate paths checked in this exact order:

PriorityPath
1scafctl/solution.yaml
2scafctl/solution.yml
3scafctl/scafctl.yaml
4scafctl/scafctl.yml
5scafctl/solution.json
6scafctl/scafctl.json
7scafctl/taskfile.yaml
8scafctl/taskfile.yml
9scafctl/actions.yaml
10scafctl/actions.yml
11.scafctl/solution.yaml
12.scafctl/solution.yml
13.scafctl/scafctl.yaml
14.scafctl/scafctl.yml
15.scafctl/solution.json
16.scafctl/scafctl.json
17.scafctl/taskfile.yaml
18.scafctl/taskfile.yml
19.scafctl/actions.yaml
20.scafctl/actions.yml
21solution.yaml
22solution.yml
23scafctl.yaml
24scafctl.yml
25solution.json
26scafctl.json
27taskfile.yaml
28taskfile.yml
29actions.yaml
30actions.yml

The first file that exists on disk is used.

Note: taskfile.yaml is NOT searched in action discovery mode (scafctl run action). It is only searched in default and solution discovery modes.

Multi-Match Ambiguity Handling#

When multiple solution files exist in a project, scafctl handles them based on command risk level:

Risk LevelCommandsBehavior
Lowrun solution, run resolver, lint, test, renderUses first match, prints a warning about other files found
Highpackage solution, catalog pushReturns an error, requires -f to disambiguate

When auto-discovery succeeds, scafctl always prints which file was selected:

Using scafctl/solution.yaml

When multiple files are found with a low-risk command:

Using scafctl/solution.yaml
WARNING: Multiple solution files found (also: solution.yaml); using first match

When multiple files are found with a high-risk command:

Error: multiple solution files found: scafctl/solution.yaml, solution.yaml; use -f/--file to specify which one

Supported Commands#

Auto-discovery works with every command that accepts -f:

CommandAuto-DiscoveryNotes
scafctl run solutionAlso supports catalog bare names and URLs
scafctl run resolverFalls back to auto-discovery when -f is omitted
scafctl lintDiscovers and lints the local solution
scafctl render solutionDiscovers solution for rendering
scafctl test functionalDiscovers solution to run functional tests
scafctl test listDiscovers solution to list test cases
scafctl test initDiscovers solution to generate test scaffold
scafctl plugins installDiscovers solution to install referenced plugins

Examples#

Basic Usage — Run in Project Directory#

# Given this project structure:
# my-project/
# ├── solution.yaml
# └── templates/
#     └── config.yaml.tpl

cd my-project
scafctl run solution          # discovers ./solution.yaml
scafctl lint                  # discovers ./solution.yaml
scafctl test functional       # discovers ./solution.yaml
# Given this project structure:
# my-project/
# ├── solution.yaml
# └── templates/
#     └── config.yaml.tpl

cd my-project
scafctl run solution          # discovers ./solution.yaml
scafctl lint                  # discovers ./solution.yaml
scafctl test functional       # discovers ./solution.yaml

Conventional Subfolder#

# Given this project structure:
# my-project/
# ├── scafctl/
# │   └── solution.yaml
# └── src/
#     └── main.go

cd my-project
scafctl run solution          # discovers ./scafctl/solution.yaml
# Given this project structure:
# my-project/
# ├── scafctl/
# │   └── solution.yaml
# └── src/
#     └── main.go

cd my-project
scafctl run solution          # discovers ./scafctl/solution.yaml

Hidden Subfolder#

# Given this project structure:
# my-project/
# ├── .scafctl/
# │   └── solution.yaml
# └── README.md

cd my-project
scafctl lint                  # discovers ./.scafctl/solution.yaml
# Given this project structure:
# my-project/
# ├── .scafctl/
# │   └── solution.yaml
# └── README.md

cd my-project
scafctl lint                  # discovers ./.scafctl/solution.yaml

Explicit -f Overrides Discovery#

When you specify -f, auto-discovery is skipped entirely:

# Use a specific file regardless of what's in the current directory
scafctl run solution -f path/to/other-solution.yaml

# Use stdin
cat solution.yaml | scafctl lint -f -

# Use a URL
scafctl run solution -f https://example.com/solution.yaml

# Use a catalog name
scafctl run solution -f my-solution@1.0.0
# Use a specific file regardless of what's in the current directory
scafctl run solution -f path/to/other-solution.yaml

# Use stdin
cat solution.yaml | scafctl lint -f -

# Use a URL
scafctl run solution -f https://example.com/solution.yaml

# Use a catalog name
scafctl run solution -f my-solution@1.0.0

Interaction with --cwd#

When --cwd is set, auto-discovery searches relative to the specified directory instead of the process working directory:

# Discover solution inside another directory
scafctl run solution --cwd /path/to/project

# This is equivalent to:
cd /path/to/project && scafctl run solution
# Discover solution inside another directory
scafctl run solution --cwd /path/to/project

# This is equivalent to:
cd /path/to/project; scafctl run solution

All 30 candidate paths are resolved against the --cwd target.

When Auto-Discovery Fails#

If no solution file is found, scafctl returns a clear error:

Error: no solution path provided and no solution file found in default locations

Common causes:

  • You’re not in the correct directory
  • The solution file has a non-standard name (use -f to specify it)
  • The --cwd flag points to the wrong directory

You can see the candidate paths scafctl checks with:

scafctl config paths
scafctl config paths

Best Practices#

  1. Use solution.yaml at the project root – this is the most common convention and is discovered without any subfolder prefix.

  2. Use scafctl/ subfolder for multi-tool repos – keeps scafctl configuration separate from other tools.

  3. Use .scafctl/ for hidden configuration – useful when the solution is infrastructure that shouldn’t be front-and-center.

  4. Use taskfile.yaml for task runner workflows – similar to how make uses Makefile or task uses Taskfile.yaml, scafctl discovers taskfile.yaml for task-oriented solutions.

  5. Always use -f in CI/CD – explicit paths prevent surprises when the working directory changes.

  6. Combine with --cwd for monorepos – target a specific project without changing directories.

  7. Avoid multiple solution files – if you must have them (e.g., both solution.yaml and taskfile.yaml), use -f with high-risk commands like package solution to avoid errors.