<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>scafctl</title><link>https://oakwood-commons.github.io/scafctl/</link><description>Recent content on scafctl</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://oakwood-commons.github.io/scafctl/index.xml" rel="self" type="application/rss+xml"/><item><title>Solutions</title><link>https://oakwood-commons.github.io/scafctl/docs/design/solutions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/solutions/</guid><description>&lt;h1 id="solutions"&gt;Solutions&lt;a class="anchor" href="#solutions"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="implementation-status"&gt;Implementation Status&lt;a class="anchor" href="#implementation-status"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Feature&lt;/th&gt;
 &lt;th&gt;Status&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Solution structure (apiVersion/kind/metadata/spec)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/solution.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Metadata fields&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Includes icon/banner beyond original design&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Catalog fields&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;visibility, beta, disabled&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Spec with resolvers&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/spec.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Workflow with actions/finally&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Uses &lt;code&gt;workflow.actions&lt;/code&gt; and &lt;code&gt;workflow.finally&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Dependencies (plugins)&lt;/td&gt;
 &lt;td&gt;⏳ Planned&lt;/td&gt;
 &lt;td&gt;Declared under &lt;code&gt;bundle.plugins&lt;/code&gt; — see &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/catalog-build-bundling/"&gt;catalog-build-bundling.md&lt;/a&gt;
&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Validation&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/spec_validation.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Run command&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;scafctl run solution&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Render command&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;scafctl render solution&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A solution is the top-level unit of configuration in scafctl. It defines &lt;em&gt;what exists&lt;/em&gt;, &lt;em&gt;how data is obtained&lt;/em&gt;, and &lt;em&gt;what actions should occur&lt;/em&gt;.&lt;/p&gt;</description></item><item><title>Resolvers</title><link>https://oakwood-commons.github.io/scafctl/docs/design/resolvers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/resolvers/</guid><description>&lt;h1 id="resolvers"&gt;Resolvers&lt;a class="anchor" href="#resolvers"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Resolvers produce named data values. They exist to gather, normalize, validate, and emit data in a deterministic way so that actions and other resolvers can consume it without re-computation or implicit behavior.&lt;/p&gt;
&lt;p&gt;Resolvers are the only mechanism for introducing data into a solution. Actions never fetch or derive data on their own.&lt;/p&gt;
&lt;p&gt;Resolvers do not cause side effects. They only compute values.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="implementation-status"&gt;Implementation Status&lt;a class="anchor" href="#implementation-status"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Feature&lt;/th&gt;
 &lt;th&gt;Status&lt;/th&gt;
 &lt;th&gt;Location&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Resolver struct (Name, Description, Type, When, etc.)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/resolver.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Resolver Context (&lt;code&gt;sync.Map&lt;/code&gt;, thread-safe)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/context.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ValueRef (Literal, Resolver, Expr, Tmpl)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/spec/valueref.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Phase-based execution (DAG ordering)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/phase.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Dependency extraction (CEL, templates, &lt;code&gt;dependsOn&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/graph.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cycle detection&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Uses &lt;code&gt;pkg/dag&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Type coercion (string, int, float, bool, array, object, any)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/spec/types.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Additional types: &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/spec/types.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Special symbols (&lt;code&gt;__self&lt;/code&gt;, &lt;code&gt;__item&lt;/code&gt;, &lt;code&gt;__index&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/executor.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Iteration aliases (&lt;code&gt;item&lt;/code&gt;, &lt;code&gt;index&lt;/code&gt; in forEach)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/spec/foreach.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Error handling (ExecutionError, AggregatedValidationError)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/errors.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Redaction for sensitive values&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;RedactedError&lt;/code&gt;, snapshots&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Timeout configuration (resolver, phase, default)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ExecutorOption&lt;/code&gt; functions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Concurrency control (&lt;code&gt;maxConcurrency&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;WithMaxConcurrency()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Progress callbacks&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ProgressCallback&lt;/code&gt; interface&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Snapshots&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/snapshot.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Graph visualization (DOT, Mermaid, ASCII, JSON)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/graph.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Prometheus metrics&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/metrics.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;forEach in transform&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ForEachClause&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;forEach &lt;code&gt;keepSkipped&lt;/code&gt; (nil retention opt-in)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ForEachClause.KeepSkipped&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;forEach nil filtering (default behavior)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/resolver/executor.go&lt;/code&gt;, &lt;code&gt;pkg/spec/foreach.go&lt;/code&gt; (&lt;code&gt;KeepSkipped&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;onError&lt;/code&gt; behavior&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ErrorBehavior&lt;/code&gt; type&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ValidateAll mode (&lt;code&gt;--validate-all&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;WithValidateAll()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;SkipValidation mode (&lt;code&gt;--skip-validation&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;WithSkipValidation()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Value size limits&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;WarnValueSize&lt;/code&gt;, &lt;code&gt;MaxValueSize&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Run resolver command&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/cmd/scafctl/run/resolver.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="responsibilities"&gt;Responsibilities&lt;a class="anchor" href="#responsibilities"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A resolver is responsible for:&lt;/p&gt;</description></item><item><title>Providers</title><link>https://oakwood-commons.github.io/scafctl/docs/design/providers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/providers/</guid><description>&lt;h1 id="providers"&gt;Providers&lt;a class="anchor" href="#providers"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Providers are stateless execution primitives. They perform a single, well-defined operation given validated inputs and return either a result or an error.&lt;/p&gt;
&lt;p&gt;Providers do not own orchestration, control flow, dependency resolution, or lifecycle decisions. This separation keeps solutions deterministic, testable, and explicit.&lt;/p&gt;
&lt;p&gt;Providers are used by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Resolvers (during resolve, transform, and validate phases)&lt;/li&gt;
&lt;li&gt;Actions (during execution or render)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Providers are never invoked implicitly. A provider runs only when explicitly referenced.&lt;/p&gt;</description></item><item><title>Actions</title><link>https://oakwood-commons.github.io/scafctl/docs/design/actions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/actions/</guid><description>&lt;h1 id="actions"&gt;Actions&lt;a class="anchor" href="#actions"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Actions describe side effects as a declarative execution graph. They exist to model what should be done, not how data is derived.&lt;/p&gt;
&lt;p&gt;Actions consume resolved data, declare dependencies, and reference results from other actions in a structured way. Actions may be executed directly by scafctl or rendered for execution by another system.&lt;/p&gt;
&lt;p&gt;Resolvers compute data.
Actions perform work.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="responsibilities"&gt;Responsibilities&lt;a class="anchor" href="#responsibilities"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An action is responsible for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Declaring an executable operation&lt;/li&gt;
&lt;li&gt;Selecting a provider&lt;/li&gt;
&lt;li&gt;Declaring dependencies on other actions&lt;/li&gt;
&lt;li&gt;Consuming resolver values and action results&lt;/li&gt;
&lt;li&gt;Defining execution conditions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An action is not responsible for:&lt;/p&gt;</description></item><item><title>Authentication</title><link>https://oakwood-commons.github.io/scafctl/docs/design/auth/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/auth/</guid><description>&lt;h1 id="authentication-and-authorization"&gt;Authentication and Authorization&lt;a class="anchor" href="#authentication-and-authorization"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Authentication in scafctl is declarative, provider-driven, and execution-agnostic.&lt;/p&gt;
&lt;p&gt;Providers declare what kind of token they require. scafctl or an external executor decides how that token is obtained and supplied. For local users, scafctl can initiate interactive authentication flows. For APIs and workflow engines, credentials are injected explicitly.&lt;/p&gt;
&lt;p&gt;Authentication is a system concern, not a provider implementation detail.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="terminology"&gt;Terminology&lt;a class="anchor" href="#terminology"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Auth Handler&lt;/strong&gt;: A component that implements the &lt;code&gt;auth.Handler&lt;/code&gt; interface and manages identity verification, credential storage, and token acquisition for a specific identity provider (e.g., Entra, GitHub). Auth handlers are registered in the auth registry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Provider&lt;/strong&gt; (in provider inputs): The &lt;code&gt;authProvider&lt;/code&gt; field in HTTP provider inputs that specifies which auth handler to use for a request.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provider&lt;/strong&gt;: Action/resolver providers that perform work (e.g., HTTP, shell, file). Distinct from auth handlers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Handler Artifact&lt;/strong&gt;: A go-plugin binary distributed via the catalog that exposes one or more auth handlers.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="built-in-vs-external-auth-handlers"&gt;Built-in vs External Auth Handlers&lt;a class="anchor" href="#built-in-vs-external-auth-handlers"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl provides built-in auth handlers for common identity providers:&lt;/p&gt;</description></item><item><title>CEL Integration</title><link>https://oakwood-commons.github.io/scafctl/docs/design/cel/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/cel/</guid><description>&lt;h1 id="cel-integration-architecture"&gt;CEL Integration Architecture&lt;a class="anchor" href="#cel-integration-architecture"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This document describes the architecture and best practices for integrating Common Expression Language (CEL) into scafctl. The design emphasizes performance through intelligent caching, thread safety through isolated execution contexts, and correctness through dependency-based execution ordering.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="architecture-principles"&gt;Architecture Principles&lt;a class="anchor" href="#architecture-principles"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="single-global-cel-environment"&gt;Single Global CEL Environment&lt;a class="anchor" href="#single-global-cel-environment"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One CEL environment per application instance&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Created at application startup&lt;/li&gt;
&lt;li&gt;Contains all built-in and custom extension functions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never recreated during runtime&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Shared across all requests and commands&lt;/li&gt;
&lt;li&gt;Enables effective AST caching&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>GitHub Auth Handler</title><link>https://oakwood-commons.github.io/scafctl/docs/design/github-auth-handler/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/github-auth-handler/</guid><description>&lt;h1 id="github-auth-handler-implementation-plan"&gt;GitHub Auth Handler Implementation Plan&lt;a class="anchor" href="#github-auth-handler-implementation-plan"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Implement a builtin GitHub auth handler (&lt;code&gt;github&lt;/code&gt;) following the established patterns from the Entra handler. The handler supports four authentication flows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Interactive (OAuth Authorization Code + PKCE)&lt;/strong&gt; — Browser-based login for local development (default)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device Code&lt;/strong&gt; — Headless/SSH fallback using OAuth device authorization grant&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PAT&lt;/strong&gt; — Personal Access Token from environment variables for CI/CD&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub App&lt;/strong&gt; — Installation token for service-to-service automation&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="design-decisions"&gt;Design Decisions&lt;a class="anchor" href="#design-decisions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="authentication-flows"&gt;Authentication Flows&lt;a class="anchor" href="#authentication-flows"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Flow&lt;/th&gt;
 &lt;th&gt;Use Case&lt;/th&gt;
 &lt;th&gt;Mechanism&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Interactive&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Local development (default)&lt;/td&gt;
 &lt;td&gt;OAuth 2.0 Authorization Code + PKCE via browser redirect&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Device Code&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Headless / SSH environments&lt;/td&gt;
 &lt;td&gt;OAuth 2.0 device authorization grant via GitHub OAuth App&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;PAT&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;CI/CD pipelines, automation&lt;/td&gt;
 &lt;td&gt;Read &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; or &lt;code&gt;GH_TOKEN&lt;/code&gt; from environment variables&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;GitHub App&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Service-to-service automation&lt;/td&gt;
 &lt;td&gt;JWT → installation access token via GitHub App credentials&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Rationale&lt;/strong&gt;: Interactive (browser) flow is the modern standard for CLI tools (&lt;code&gt;gh&lt;/code&gt;, &lt;code&gt;az&lt;/code&gt;, &lt;code&gt;gcloud&lt;/code&gt; all use it as their default). Device code is the fallback for headless environments. PAT from environment mirrors the Entra handler&amp;rsquo;s service principal pattern and aligns with GitHub Actions&amp;rsquo; &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; injection. GitHub App flow enables automated workflows that need repository access without a user context.&lt;/p&gt;</description></item><item><title>Catalog</title><link>https://oakwood-commons.github.io/scafctl/docs/design/catalog/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/catalog/</guid><description>&lt;h1 id="scafctl-catalog-system"&gt;scafctl Catalog System&lt;a class="anchor" href="#scafctl-catalog-system"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl manages artifact lifecycle through a workflow analogous to container images, using OCI artifacts for storage and distribution. This design enables version control, dependency management, and consistent deployment across environments for solutions, providers, auth handlers, and other scafctl artifacts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="core-concepts"&gt;Core Concepts&lt;a class="anchor" href="#core-concepts"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="artifacts"&gt;Artifacts&lt;a class="anchor" href="#artifacts"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The catalog system supports multiple artifact types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solutions&lt;/strong&gt;: YAML configuration files that define resolvers, actions, and dependencies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Providers&lt;/strong&gt;: Binary executables that provide custom providers using hashicorp/go-plugin over gRPC&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Handlers&lt;/strong&gt;: Binary executables that provide authentication handlers using hashicorp/go-plugin over gRPC&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future artifact types&lt;/strong&gt;: TBD as the system evolves&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="catalogs"&gt;Catalogs&lt;a class="anchor" href="#catalogs"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Local catalog&lt;/strong&gt;: Functions like Docker&amp;rsquo;s local image store, caching built and pulled artifacts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote catalog&lt;/strong&gt;: Centralized OCI registry with GUI frontend for artifact discovery and distribution&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="artifact-identification"&gt;Artifact Identification&lt;a class="anchor" href="#artifact-identification"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Artifacts are distinguished using OCI media types and annotations:&lt;/p&gt;</description></item><item><title>GCP Auth Handler</title><link>https://oakwood-commons.github.io/scafctl/docs/design/gcp-auth-handler/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/gcp-auth-handler/</guid><description>&lt;h1 id="gcp-auth-handler-implementation-plan"&gt;GCP Auth Handler Implementation Plan&lt;a class="anchor" href="#gcp-auth-handler-implementation-plan"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Implement a builtin GCP auth handler (&lt;code&gt;gcp&lt;/code&gt;) following the established patterns from the Entra and GitHub handlers. The handler will support four authentication flows: Application Default Credentials (ADC) for interactive use, Service Account Key for CI/CD, Workload Identity Federation for GKE/cross-cloud, and GCE Metadata Server for cloud-hosted workloads. Service account impersonation will be supported across all flows.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="design-decisions"&gt;Design Decisions&lt;a class="anchor" href="#design-decisions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="authentication-flows"&gt;Authentication Flows&lt;a class="anchor" href="#authentication-flows"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Flow&lt;/th&gt;
 &lt;th&gt;Use Case&lt;/th&gt;
 &lt;th&gt;Mechanism&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;ADC (Application Default Credentials)&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Interactive CLI use&lt;/td&gt;
 &lt;td&gt;OAuth 2.0 authorization code + PKCE via browser, with gcloud ADC fallback&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Service Account Key&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;CI/CD pipelines, automation&lt;/td&gt;
 &lt;td&gt;JWT assertion from JSON key file via &lt;code&gt;GOOGLE_APPLICATION_CREDENTIALS&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Workload Identity Federation&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;GKE, cross-cloud (AWS/Azure/OIDC)&lt;/td&gt;
 &lt;td&gt;STS token exchange for federated external tokens&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Metadata Server&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;GCE, Cloud Run, GKE&lt;/td&gt;
 &lt;td&gt;Token from &lt;code&gt;http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Flow auto-detection priority&lt;/strong&gt;: Workload Identity Federation &amp;gt; Metadata Server &amp;gt; Service Account Key &amp;gt; ADC (stored credentials).&lt;/p&gt;</description></item><item><title>CLI</title><link>https://oakwood-commons.github.io/scafctl/docs/design/cli/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/cli/</guid><description>&lt;h1 id="cli-usage"&gt;CLI Usage&lt;a class="anchor" href="#cli-usage"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This document describes how to invoke scafctl from the command line. The CLI follows a kubectl-style structure where verbs, kinds, and names are explicit and positional.&lt;/p&gt;
&lt;p&gt;The general pattern is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl &amp;lt;verb&amp;gt; &amp;lt;kind&amp;gt; &amp;lt;name[@version(or constraint)]&amp;gt; [flags]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;verb&amp;gt;&lt;/code&gt; describes what you want to do&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;kind&amp;gt;&lt;/code&gt; identifies the type of object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; identifies the object&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@version&lt;/code&gt; is optional and resolved via the catalog ( or constraint)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="implementation-status"&gt;Implementation Status&lt;a class="anchor" href="#implementation-status"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Command&lt;/th&gt;
 &lt;th&gt;Status&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;run solution&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Requires workflow (errors if no workflow defined; use &lt;code&gt;run resolver&lt;/code&gt; for resolver-only)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;run resolver&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Resolver-only execution for debugging and inspection&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;render solution&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Includes action-graph and snapshot modes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;get solution/provider/resolver&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;explain solution/provider&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;config *&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;view, get, set, unset, add-catalog, remove-catalog, use-catalog, init, schema, validate&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;snapshot show/diff&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;solution diff&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Structural comparison of two solution files&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;secrets *&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;list, get, set, delete, exists, export, import, rotate&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;auth *&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;login, logout, status, token&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;resolver graph&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;❌ Removed&lt;/td&gt;
 &lt;td&gt;Use &lt;code&gt;run resolver --graph&lt;/code&gt; instead&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;build solution&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Catalog feature&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;catalog list/inspect/delete/prune&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Catalog management&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;catalog save/load&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Offline distribution&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;eval cel&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Evaluate CEL expressions from CLI&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;eval template&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Evaluate Go templates from CLI&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;eval validate&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Validate solution files from CLI&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;new solution&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Scaffold a new solution from template&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;lint rules&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;List all available lint rules&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;lint explain&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Explain a specific lint rule&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;examples list&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;List available example configurations&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;examples get&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Get/download an example file&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;push solution/plugin&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;📋 Planned&lt;/td&gt;
 &lt;td&gt;Remote catalog feature&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;pull solution/plugin&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;📋 Planned&lt;/td&gt;
 &lt;td&gt;Remote catalog feature&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;tag solution/plugin&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;📋 Planned&lt;/td&gt;
 &lt;td&gt;Catalog feature&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--catalog&lt;/code&gt; flag&lt;/td&gt;
 &lt;td&gt;📋 Planned&lt;/td&gt;
 &lt;td&gt;Catalog feature&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Version constraints (&lt;code&gt;@^1.2&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;📋 Planned&lt;/td&gt;
 &lt;td&gt;Requires catalog&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="core-concepts"&gt;Core Concepts&lt;a class="anchor" href="#core-concepts"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="kinds"&gt;Kinds&lt;a class="anchor" href="#kinds"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;solution&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resolver&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;catalog&lt;/code&gt; &lt;em&gt;(planned)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="names-and-versions"&gt;Names and Versions&lt;a class="anchor" href="#names-and-versions"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Names identify an object within a kind.&lt;/p&gt;</description></item><item><title>Plugins</title><link>https://oakwood-commons.github.io/scafctl/docs/design/plugins/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/plugins/</guid><description>&lt;h1 id="plugins"&gt;Plugins&lt;a class="anchor" href="#plugins"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Plugins are the extension mechanism for scafctl. They allow external binaries to contribute functionality to the system in a controlled, versioned, and discoverable way.&lt;/p&gt;
&lt;p&gt;The primary purpose of plugins is to supply providers and auth handlers. &amp;ldquo;Plugin&amp;rdquo; is an internal implementation term - users interact with &amp;ldquo;providers&amp;rdquo; and &amp;ldquo;auth handlers&amp;rdquo; as catalog artifact kinds.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="terminology"&gt;Terminology&lt;a class="anchor" href="#terminology"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Plugin&lt;/strong&gt;: Internal term for a go-plugin binary. Not exposed to users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provider Artifact&lt;/strong&gt;: A plugin binary distributed via the catalog that exposes one or more providers. Users push/pull &amp;ldquo;providers&amp;rdquo; not &amp;ldquo;plugins&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auth Handler Artifact&lt;/strong&gt;: A plugin binary distributed via the catalog that exposes one or more auth handlers.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="what-a-plugin-is"&gt;What a Plugin Is&lt;a class="anchor" href="#what-a-plugin-is"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A plugin is an external process that implements one or more scafctl extension interfaces and communicates with scafctl over RPC.&lt;/p&gt;</description></item><item><title>Getting Started</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/getting-started/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/getting-started/</guid><description>&lt;h1 id="getting-started-with-scafctl"&gt;Getting Started with scafctl&lt;a class="anchor" href="#getting-started-with-scafctl"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide will help you get up and running with scafctl in under 10 minutes.&lt;/p&gt;
&lt;h2 id="what-is-scafctl"&gt;What is scafctl?&lt;a class="anchor" href="#what-is-scafctl"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl is a CLI tool for declarative configuration and workflow automation. It uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resolvers&lt;/strong&gt; to gather and transform data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actions&lt;/strong&gt; to perform side effects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Providers&lt;/strong&gt; as the execution primitives for both&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Think of it as a way to define &amp;ldquo;what you want&amp;rdquo; (data + operations) in YAML, and let scafctl figure out &amp;ldquo;how to do it&amp;rdquo; (dependency order, parallelization, error handling).&lt;/p&gt;</description></item><item><title>Hugo Guide</title><link>https://oakwood-commons.github.io/scafctl/docs/hugo-guide/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/hugo-guide/</guid><description>&lt;h1 id="hugo-guide-for-scafctl"&gt;Hugo Guide for scafctl&lt;a class="anchor" href="#hugo-guide-for-scafctl"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide explains how to set up and use Hugo for the scafctl documentation site.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go 1.21+ installed (Hugo extended is recommended)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installation"&gt;Installation&lt;a class="anchor" href="#installation"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="option-1-using-homebrew-macos"&gt;Option 1: Using Homebrew (macOS)&lt;a class="anchor" href="#option-1-using-homebrew-macos"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brew install hugo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="option-2-using-go"&gt;Option 2: Using Go&lt;a class="anchor" href="#option-2-using-go"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go install github.com/gohugoio/hugo@latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="option-3-download-binary"&gt;Option 3: Download Binary&lt;a class="anchor" href="#option-3-download-binary"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Download from &lt;a href="https://github.com/gohugoio/hugo/releases" target="_blank" rel="noopener noreferrer"&gt;Hugo Releases&lt;/a&gt;
 and add to your PATH.&lt;/p&gt;
&lt;h3 id="verify-installation"&gt;Verify Installation&lt;a class="anchor" href="#verify-installation"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hugo version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="initial-setup-one-time"&gt;Initial Setup (One-time)&lt;a class="anchor" href="#initial-setup-one-time"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After cloning the repository, initialize Hugo modules and download the theme:&lt;/p&gt;</description></item><item><title>Testing</title><link>https://oakwood-commons.github.io/scafctl/docs/design/testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/testing/</guid><description>&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Testing in scafctl ensures that solutions behave correctly, deterministically, and safely before performing side effects.&lt;/p&gt;
&lt;p&gt;scafctl separates data resolution, transformation, and execution. Solution-level testing requires no mocks — render mode produces a fully concrete execution plan without side effects. At the package level, providers and services use test doubles to isolate external dependencies.&lt;/p&gt;
&lt;p&gt;Testing is an outcome of the design, not a separate subsystem.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="core-principles"&gt;Core Principles&lt;a class="anchor" href="#core-principles"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;All data enters through resolvers&lt;/li&gt;
&lt;li&gt;All computation is provider-backed&lt;/li&gt;
&lt;li&gt;All side effects are isolated to actions&lt;/li&gt;
&lt;li&gt;Render mode produces a fully concrete execution plan&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because of this:&lt;/p&gt;</description></item><item><title>Miscellaneous</title><link>https://oakwood-commons.github.io/scafctl/docs/design/misc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/misc/</guid><description>&lt;h1 id="miscellaneous-design-considerations"&gt;Miscellaneous Design Considerations&lt;a class="anchor" href="#miscellaneous-design-considerations"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This document captures cross-cutting concepts that are intentionally not core primitives, but are required to make scafctl safe, predictable, and operable at scale.&lt;/p&gt;
&lt;p&gt;These concerns apply across resolvers, actions, providers, plugins, and solutions.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="implementation-status"&gt;Implementation Status&lt;a class="anchor" href="#implementation-status"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Concern&lt;/th&gt;
 &lt;th&gt;Status&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Schema and Typing Model&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Provider &lt;code&gt;Descriptor&lt;/code&gt; with &lt;code&gt;Schema&lt;/code&gt; and &lt;code&gt;OutputSchemas&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Provider Contracts&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Full descriptor with input/output schemas, capabilities&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Provider Capabilities&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;from&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;, &lt;code&gt;validation&lt;/code&gt;, &lt;code&gt;authentication&lt;/code&gt;, &lt;code&gt;action&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Secrets and Sensitive Data&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/secrets&lt;/code&gt; with AES-256-GCM, keychain integration&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Secret Redaction&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;RedactedError&lt;/code&gt;, &lt;code&gt;--redact&lt;/code&gt; flag on snapshots&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Stateless Core&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Providers are stateless, no persistent state&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Error Model&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Rich error types with location, cause, context&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Determinism Rules&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Resolver purity enforced, &lt;code&gt;WhatIf&lt;/code&gt; functions declared&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Resolver DAG Visualization&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;ASCII, DOT, Mermaid, JSON formats&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Action DAG Visualization&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;ASCII, DOT, Mermaid, JSON formats via &lt;code&gt;--action-graph&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Validation&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Schema, dependency, type validation&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Linting&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;scafctl lint&lt;/code&gt; with error/warning/info severities&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Extensibility (Providers/Plugins)&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;Plugin system for external providers&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Render vs Run Separation&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;scafctl render&lt;/code&gt; vs &lt;code&gt;scafctl run&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Dry-run Mode&lt;/td&gt;
 &lt;td&gt;✅ Implemented&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--dry-run&lt;/code&gt; flag, &lt;code&gt;WhatIf&lt;/code&gt; on Descriptor, &lt;code&gt;DryRunFromContext()&lt;/code&gt; for provider-level&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="schema-and-typing-model"&gt;Schema and Typing Model&lt;a class="anchor" href="#schema-and-typing-model"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote class='book-hint '&gt;
&lt;p&gt;&lt;strong&gt;Status&lt;/strong&gt;: ✅ Implemented in &lt;code&gt;pkg/provider/provider.go&lt;/code&gt;&lt;/p&gt;</description></item><item><title>CLI Contributing</title><link>https://oakwood-commons.github.io/scafctl/docs/design/cli-contributing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/cli-contributing/</guid><description>&lt;h1 id="cli-implementation-guide"&gt;CLI Implementation Guide&lt;a class="anchor" href="#cli-implementation-guide"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This document describes how to implement CLI commands in scafctl. It provides patterns, code examples, and best practices based on the existing codebase.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#architecture-overview"&gt;Architecture Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#package-structure"&gt;Package Structure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#creating-a-new-command"&gt;Creating a New Command&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#command-components"&gt;Command Components&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#terminal-output"&gt;Terminal Output&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#data-output-with-kvx"&gt;Data Output with kvx&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#flags-and-parameters"&gt;Flags and Parameters&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#context-management"&gt;Context Management&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#testing-commands"&gt;Testing Commands&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-patterns"&gt;Common Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#checklist"&gt;Checklist&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="architecture-overview"&gt;Architecture Overview&lt;a class="anchor" href="#architecture-overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The scafctl CLI follows a kubectl-style command structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl &amp;lt;verb&amp;gt; &amp;lt;kind&amp;gt; &amp;lt;name[@version]&amp;gt; [flags]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The CLI is built using &lt;a href="https://github.com/spf13/cobra" target="_blank" rel="noopener noreferrer"&gt;Cobra&lt;/a&gt;
 and organized into a hierarchical command tree:&lt;/p&gt;</description></item><item><title>Functional Testing</title><link>https://oakwood-commons.github.io/scafctl/docs/design/functional-testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/functional-testing/</guid><description>&lt;h1 id="functional-testing"&gt;Functional Testing&lt;a class="anchor" href="#functional-testing"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Functional testing validates that solutions behave correctly by executing scafctl commands against them and asserting on the output. Solution authors define test cases inline in their solution spec. The &lt;code&gt;scafctl test functional&lt;/code&gt; command discovers tests, sets up isolated sandboxes, runs builtin and user-defined tests, and reports results.&lt;/p&gt;
&lt;p&gt;This is the primary mechanism for validating solutions in CI and during development.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="implementation-status"&gt;Implementation Status&lt;a class="anchor" href="#implementation-status"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Feature&lt;/th&gt;
 &lt;th&gt;Status&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;test functional&lt;/code&gt; CLI command&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/cmd/scafctl/test/functional.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;test list&lt;/code&gt; CLI subcommand&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/cmd/scafctl/test/list.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Test spec types&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/types.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Builtin tests&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Parse, resolve, render, lint in &lt;code&gt;builtins.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Command-based test execution&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;In-process cobra execution via &lt;code&gt;CommandBuilder&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CEL assertions&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/assertions.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Regex assertions&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Contains assertions&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Negation assertions&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;notContains&lt;/code&gt;, &lt;code&gt;notRegex&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Golden file snapshots&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/snapshot.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Init scripts (exec provider)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;InitStep&lt;/code&gt; with exec provider schema&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Test file includes&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;TestInclude&lt;/code&gt; discovery source in bundler&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Temp directory sandbox&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/sandbox.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;JUnit XML reporting&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/junit.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Compose support for tests&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;mergeTests()&lt;/code&gt; and &lt;code&gt;mergeTestConfig()&lt;/code&gt; in compose&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Parallel test execution&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Semaphore-based concurrency control&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CEL assertion diagnostics&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/diagnostics.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Suite-level setup&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;testing.config.setup&lt;/code&gt; with base sandbox copy&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Test tags and filtering&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--tag&lt;/code&gt; flag, &lt;code&gt;tags&lt;/code&gt; field on test cases&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Per-test environment variables&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;env&lt;/code&gt; field on test cases&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cleanup steps&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cleanup&lt;/code&gt; field, runs even on failure&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Test inheritance (extends)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/inheritance.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Assertion target (stderr)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;target&lt;/code&gt; field: &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;stderr&lt;/code&gt;, &lt;code&gt;combined&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;File assertions (&lt;code&gt;__files&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Diff-based sandbox file change detection&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Fail-fast (per-solution)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--fail-fast&lt;/code&gt; stops remaining tests per solution&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Test name validation&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Enforced in &lt;code&gt;TestCase.Validate()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Selective builtin skip&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;SkipBuiltinsValue&lt;/code&gt; with custom unmarshal&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;In-process command execution&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Root()&lt;/code&gt; with &lt;code&gt;*RootOptions&lt;/code&gt;, &lt;code&gt;CommandBuilder&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Concurrency control&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;-j&lt;/code&gt; flag, &lt;code&gt;--sequential&lt;/code&gt; as sugar for &lt;code&gt;-j 1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Conditional skip (CEL &lt;code&gt;skip&lt;/code&gt; expression)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;CEL-based runtime skip evaluation&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Test retries&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;retries&lt;/code&gt; field for flaky test resilience&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Suite-level cleanup&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;testing.config.cleanup&lt;/code&gt; for teardown after all tests&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;File size guard&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Cap &lt;code&gt;files[].content&lt;/code&gt; at 10MB to prevent OOM&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;In-process execution safety&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Root()&lt;/code&gt; accepts &lt;code&gt;*RootOptions&lt;/code&gt;, no package-level state&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Unused template lint warning&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;unused-template&lt;/code&gt; lint rule&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Solution filtering (&lt;code&gt;--solution&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Glob-based solution name filtering&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--filter&lt;/code&gt; solution/test format&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--filter &amp;quot;solution/test-name&amp;quot;&lt;/code&gt; glob support&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--dry-run&lt;/code&gt; flag&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Validate test definitions without executing&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Suite-level &lt;code&gt;env&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;testing.config.env&lt;/code&gt; shared across all tests&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Binary file content guard&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Non-UTF-8 files get &lt;code&gt;content&lt;/code&gt; set to &lt;code&gt;&amp;quot;&amp;lt;binary file&amp;gt;&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Test execution ordering&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Alphabetical by name; builtins first&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Field max limits&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;assertions: 100&lt;/code&gt;, &lt;code&gt;files: 50&lt;/code&gt;, &lt;code&gt;tags: 20&lt;/code&gt;, extends depth: 10&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Glob zero-match error&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Test &lt;code&gt;files&lt;/code&gt; globs matching zero files produce &lt;code&gt;error&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Environment precedence chain&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;process → &lt;code&gt;testing.config.env&lt;/code&gt; → &lt;code&gt;TestCase.env&lt;/code&gt; → &lt;code&gt;InitStep.env&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;TestCase.Validate()&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Comprehensive test case validation method&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Extends non-existent error&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;extends&lt;/code&gt; referencing non-existent test names is a parse-time error&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Tests per solution limit&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;Max 500 tests per solution&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Watch mode (&lt;code&gt;--watch&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;fsnotify&lt;/code&gt;-based file watcher in &lt;code&gt;soltesting/watch.go&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Auto-generated tests (&lt;code&gt;-o test&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;✅ Done&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pkg/solution/soltesting/generate.go&lt;/code&gt;; wired into &lt;code&gt;render solution&lt;/code&gt;, &lt;code&gt;run resolver&lt;/code&gt;, &lt;code&gt;run solution&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="test-definition"&gt;Test Definition&lt;a class="anchor" href="#test-definition"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="location"&gt;Location&lt;a class="anchor" href="#location"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tests are defined under &lt;code&gt;spec.testing.cases&lt;/code&gt; in the solution YAML. Like resolvers, tests support the &lt;code&gt;compose&lt;/code&gt; mechanism for splitting into separate files.&lt;/p&gt;</description></item><item><title>Future Enhancements</title><link>https://oakwood-commons.github.io/scafctl/docs/design/future-enhancements/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/future-enhancements/</guid><description>&lt;h1 id="future-enhancements"&gt;Future Enhancements&lt;a class="anchor" href="#future-enhancements"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Consolidated index of planned features and future enhancements across all design docs. Each entry links back to the source design doc for full context.&lt;/p&gt;
&lt;p&gt;Items marked ✅ have been implemented since this document was originally written.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="actions"&gt;Actions&lt;a class="anchor" href="#actions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Source: &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/actions/"&gt;actions.md&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id="-result-schema-validation"&gt;✅ Result Schema Validation&lt;a class="anchor" href="#-result-schema-validation"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Implemented.&lt;/strong&gt; Actions can declare a &lt;code&gt;resultSchema&lt;/code&gt; with JSON Schema and a &lt;code&gt;resultSchemaMode&lt;/code&gt; (&lt;code&gt;error&lt;/code&gt;, &lt;code&gt;warn&lt;/code&gt;, &lt;code&gt;ignore&lt;/code&gt;). Validated at runtime in the action executor. Supports workflow-level defaults. See &lt;code&gt;pkg/action/result_validation.go&lt;/code&gt; and &lt;code&gt;pkg/action/executor.go&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Dry-Run &amp; WhatIf</title><link>https://oakwood-commons.github.io/scafctl/docs/design/dryrun-whatif/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/dryrun-whatif/</guid><description>&lt;h1 id="dry-run--whatif-architecture"&gt;Dry-Run &amp;amp; WhatIf Architecture&lt;a class="anchor" href="#dry-run--whatif-architecture"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This document describes the two complementary dry-run mechanisms in scafctl and how they interact.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl has two distinct dry-run paths:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Mechanism&lt;/th&gt;
 &lt;th&gt;Scope&lt;/th&gt;
 &lt;th&gt;Command&lt;/th&gt;
 &lt;th&gt;How it works&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;WhatIf&lt;/strong&gt; (solution-level)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;run solution --dry-run&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Solution dry-run&lt;/td&gt;
 &lt;td&gt;Resolvers execute normally (side-effect-free); actions are &lt;strong&gt;never invoked&lt;/strong&gt; — each action&amp;rsquo;s provider generates a WhatIf description&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;DryRunFromContext&lt;/strong&gt; (provider-level)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;run provider --dry-run&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Provider dry-run&lt;/td&gt;
 &lt;td&gt;The provider&amp;rsquo;s &lt;code&gt;Execute()&lt;/code&gt; method is called with &lt;code&gt;DryRunFromContext(ctx) == true&lt;/code&gt;; providers return mock data&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="why-two-mechanisms"&gt;Why Two Mechanisms?&lt;a class="anchor" href="#why-two-mechanisms"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solution-level dry-run&lt;/strong&gt; answers &amp;ldquo;what would this solution do?&amp;rdquo; — it needs real resolver values to materialize action inputs and generate accurate WhatIf messages. Since resolvers are side-effect-free by design, they run normally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provider-level dry-run&lt;/strong&gt; answers &amp;ldquo;what would this provider return?&amp;rdquo; — useful for testing a single provider in isolation. The provider itself decides what mock data to return.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="solution-level-dry-run-whatif"&gt;Solution-Level Dry-Run (WhatIf)&lt;a class="anchor" href="#solution-level-dry-run-whatif"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="flow"&gt;Flow&lt;a class="anchor" href="#flow"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌──────────────────┐ ┌────────────────────┐ ┌─────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Execute resolvers │────&amp;gt;│ dryrun.Generate() │────&amp;gt;│ WhatIf Report │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ (real data) │ │ │ │ (JSON/YAML/ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ │ For each action: │ │ table) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ │ - Materialize │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ │ inputs │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ │ - Call provider&amp;#39;s │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ │ DescribeWhatIf() │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────────┘ └────────────────────┘ └─────────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Resolvers execute normally — they are side-effect-free, so real data is available&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dryrun.Generate()&lt;/code&gt; builds the action graph and materializes inputs using real resolver data&lt;/li&gt;
&lt;li&gt;For each action, &lt;code&gt;Descriptor.DescribeWhatIf(ctx, inputs)&lt;/code&gt; is called to get a provider-specific message&lt;/li&gt;
&lt;li&gt;Actions are &lt;strong&gt;never&lt;/strong&gt; executed — only their WhatIf descriptions are used&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="whatif-on-descriptor"&gt;WhatIf on Descriptor&lt;a class="anchor" href="#whatif-on-descriptor"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Providers implement &lt;code&gt;WhatIf&lt;/code&gt; on their &lt;code&gt;Descriptor&lt;/code&gt; to generate context-specific descriptions:&lt;/p&gt;</description></item><item><title>Solution Provider</title><link>https://oakwood-commons.github.io/scafctl/docs/design/solution-provider/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/solution-provider/</guid><description>&lt;h1 id="solution-provider"&gt;Solution Provider&lt;a class="anchor" href="#solution-provider"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Date:&lt;/strong&gt; February 9, 2026&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="design-philosophy"&gt;Design Philosophy&lt;a class="anchor" href="#design-philosophy"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Three guiding principles:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fail loud by default, opt into silence.&lt;/strong&gt; Sub-solution failures should be Go errors unless the user explicitly asks for envelope-only reporting. This prevents the most common mistake (forgetting to check &lt;code&gt;status&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reuse existing types everywhere.&lt;/strong&gt; The codebase already has &lt;code&gt;ValueRef&lt;/code&gt;, &lt;code&gt;get.Interface&lt;/code&gt;, &lt;code&gt;resolver.Context&lt;/code&gt;, &lt;code&gt;action.ExecutionResult&lt;/code&gt;, etc. The solution provider should compose these, not reinvent them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Separation of loading vs execution.&lt;/strong&gt; The provider should do one thing — execute a loaded solution. Loading is delegated entirely to &lt;code&gt;get.Interface&lt;/code&gt;. This makes testing trivial and keeps the provider focused.&lt;/p&gt;</description></item><item><title>State</title><link>https://oakwood-commons.github.io/scafctl/docs/design/state/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/state/</guid><description>&lt;h1 id="state"&gt;State&lt;a class="anchor" href="#state"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="purpose"&gt;Purpose&lt;a class="anchor" href="#purpose"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;State adds optional, per-solution persistence of resolver values across executions. It enables two primary workflows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Re-run with same data&lt;/strong&gt; — Execute a solution repeatedly and retain resolved values between runs without re-prompting or re-fetching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation replay&lt;/strong&gt; — A validation application can replay the exact command with the same flags and verify it produces the same results.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;State is opt-in. Solutions without a &lt;code&gt;state&lt;/code&gt; block behave exactly as they do today — stateless, deterministic, and self-contained. State does not change the resolver or provider execution model. It adds a persistence layer accessed exclusively through the provider system.&lt;/p&gt;</description></item><item><title>Catalog Build Bundling</title><link>https://oakwood-commons.github.io/scafctl/docs/design/catalog-build-bundling/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/catalog-build-bundling/</guid><description>&lt;h1 id="solution-file-bundling"&gt;Solution File Bundling&lt;a class="anchor" href="#solution-file-bundling"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Date:&lt;/strong&gt; February 9, 2026&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="problem-statement"&gt;Problem Statement&lt;a class="anchor" href="#problem-statement"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a solution is built (&lt;code&gt;scafctl build solution&lt;/code&gt;) and pushed to a catalog, only the solution YAML file is stored as a single OCI layer. Three categories of dependencies are lost:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Local file references&lt;/strong&gt; — template files read by the &lt;code&gt;file&lt;/code&gt; provider, sub-solutions used by the &lt;code&gt;solution&lt;/code&gt; provider, or other local resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-file solution parts&lt;/strong&gt; — solutions split across multiple YAML files (e.g., &lt;code&gt;resolvers.yaml&lt;/code&gt;, &lt;code&gt;workflow.yaml&lt;/code&gt;) that compose the complete solution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote catalog dependencies&lt;/strong&gt; — sub-solutions referenced by catalog name (e.g., &lt;code&gt;deploy-to-k8s@2.0.0&lt;/code&gt;) that must be fetched from a registry at runtime.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This means solutions are not portable across machines, teams, or environments.&lt;/p&gt;</description></item><item><title>Output Directory</title><link>https://oakwood-commons.github.io/scafctl/docs/design/output-dir/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/output-dir/</guid><description>&lt;h1 id="output-directory"&gt;Output Directory&lt;a class="anchor" href="#output-directory"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;--output-dir&lt;/code&gt; flag scopes the action/workflow phase to a target directory, creating a clear phase-based separation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resolvers&lt;/strong&gt; always operate in CWD (current working directory) — they gather data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actions&lt;/strong&gt; operate in the output directory when &lt;code&gt;--output-dir&lt;/code&gt; is set — they produce output&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When &lt;code&gt;--output-dir&lt;/code&gt; is not set, actions continue using CWD (backward compatible).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="mental-model"&gt;Mental Model&lt;a class="anchor" href="#mental-model"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CWD (current working directory)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── solution.yaml ← parsed by scafctl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── templates/ ← read by resolvers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── app.yaml.tpl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── data/ ← read by resolvers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── config.json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;--output-dir /path/to/output
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── app.yaml ← written by actions
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── config/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── settings.json ← written by actions
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── scripts/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── deploy.sh ← written by actions&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="phase-semantics"&gt;Phase Semantics&lt;a class="anchor" href="#phase-semantics"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Phase&lt;/th&gt;
 &lt;th&gt;Directory&lt;/th&gt;
 &lt;th&gt;Behavior&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Resolver&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;CWD (always)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;file&lt;/code&gt; provider reads from CWD, &lt;code&gt;directory&lt;/code&gt; lists CWD, etc.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Action&lt;/strong&gt; (with &lt;code&gt;--output-dir&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;Output directory&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;file&lt;/code&gt; write goes to output-dir, &lt;code&gt;directory&lt;/code&gt; mkdir goes to output-dir&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Action&lt;/strong&gt; (without flag)&lt;/td&gt;
 &lt;td&gt;CWD&lt;/td&gt;
 &lt;td&gt;Same as today — full backward compatibility&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="usage"&gt;Usage&lt;a class="anchor" href="#usage"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="cli-flag"&gt;CLI Flag&lt;a class="anchor" href="#cli-flag"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Actions write to /tmp/output instead of CWD&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run solution -f solution.yaml --output-dir /tmp/output
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Dry-run with output-dir shows target paths&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run solution -f solution.yaml --output-dir /tmp/output --dry-run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Run resolvers only (--output-dir accepted but has no effect)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run resolver -f solution.yaml --output-dir /tmp/output -o json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Run a specific provider in action mode with output-dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run provider file --capability action --output-dir /tmp/output &lt;span style="color:#79c0ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -i &lt;span style="color:#a5d6ff"&gt;&amp;#39;{&amp;#34;operation&amp;#34;: &amp;#34;write&amp;#34;, &amp;#34;path&amp;#34;: &amp;#34;hello.txt&amp;#34;, &amp;#34;content&amp;#34;: &amp;#34;world&amp;#34;}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="default-setting"&gt;Default Setting&lt;a class="anchor" href="#default-setting"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A default output directory can be configured in the app config so you don&amp;rsquo;t need to pass the flag every time:&lt;/p&gt;</description></item><item><title>Solution Scaffolding Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/scaffolding-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/scaffolding-tutorial/</guid><description>&lt;h1 id="solution-scaffolding-tutorial"&gt;Solution Scaffolding Tutorial&lt;a class="anchor" href="#solution-scaffolding-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers using &lt;code&gt;scafctl new solution&lt;/code&gt; to quickly scaffold new solution files with the correct structure, providers, and best practices.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;new solution&lt;/code&gt; command generates a complete, valid solution YAML file based on your inputs. Instead of writing YAML from scratch (and getting field names wrong), scaffolding gives you a working starting point.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Parameters&amp;lt;br/&amp;gt;(name, etc)&amp;#34;] --&amp;gt; B[&amp;#34;scafctl&amp;lt;br/&amp;gt;new solution&amp;#34;] --&amp;gt; C[&amp;#34;Solution&amp;lt;br/&amp;gt;YAML File&amp;#34;]&lt;/pre&gt;&lt;h2 id="1-quick-start"&gt;1. Quick Start&lt;a class="anchor" href="#1-quick-start"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="generate-a-basic-solution"&gt;Generate a Basic Solution&lt;a class="anchor" href="#generate-a-basic-solution"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="book-tabs"&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-0" checked="checked" /&gt;&lt;label for="tabs-0-0"&gt;Bash&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl new solution &lt;span style="color:#79c0ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --name my-app &lt;span style="color:#79c0ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --description &lt;span style="color:#a5d6ff"&gt;&amp;#34;My application configuration&amp;#34;&lt;/span&gt; &lt;span style="color:#79c0ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --output my-app.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-1" /&gt;&lt;label for="tabs-0-1"&gt;PowerShell&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl new solution `
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --name my-app `
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --description &lt;span style="color:#a5d6ff"&gt;&amp;#34;My application configuration&amp;#34;&lt;/span&gt; `
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --output my-app.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This generates a valid solution file with:&lt;/p&gt;</description></item><item><title>Catalog CLI Design Decision</title><link>https://oakwood-commons.github.io/scafctl/docs/design/catalog-cli-design-decision/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/catalog-cli-design-decision/</guid><description>&lt;h1 id="catalog-cli-design-decision-pushpull-reference-patterns"&gt;Catalog CLI Design Decision: Push/Pull Reference Patterns&lt;a class="anchor" href="#catalog-cli-design-decision-pushpull-reference-patterns"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; Decided — Option B&lt;br&gt;
&lt;strong&gt;Created:&lt;/strong&gt; 2026-02-06&lt;br&gt;
&lt;strong&gt;Decided:&lt;/strong&gt; 2026-02-07&lt;br&gt;
&lt;strong&gt;Decision:&lt;/strong&gt; Keep current &lt;code&gt;--catalog&lt;/code&gt; flag approach with config-based default catalog resolution.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Currently, &lt;code&gt;scafctl catalog push&lt;/code&gt; requires a &lt;code&gt;--catalog&lt;/code&gt; flag to specify the target registry:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl catalog push my-solution@1.0.0 --catalog ghcr.io/myorg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Pushes to: ghcr.io/myorg/solutions/my-solution:1.0.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This differs from docker/podman, which uses full image names:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker tag my-image ghcr.io/myorg/my-image:1.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker push ghcr.io/myorg/my-image:1.0.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We need to decide if we should align with the docker pattern, keep the current approach, or support both.&lt;/p&gt;</description></item><item><title>Working Directory (--cwd)</title><link>https://oakwood-commons.github.io/scafctl/docs/design/cwd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/cwd/</guid><description>&lt;h1 id="working-directory---cwd"&gt;Working Directory (&lt;code&gt;--cwd&lt;/code&gt;)&lt;a class="anchor" href="#working-directory---cwd"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;--cwd&lt;/code&gt; (short: &lt;code&gt;-C&lt;/code&gt;) global flag changes the logical working directory for all path resolution without mutating the process CWD. It behaves similarly to &lt;code&gt;git -C&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl --cwd /path/to/project run solution -f solution.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl -C /path/to/project run resolver -f demo.yaml -o json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When &lt;code&gt;--cwd&lt;/code&gt; is set, &lt;strong&gt;all&lt;/strong&gt; relative paths—including &lt;code&gt;-f&lt;/code&gt;, &lt;code&gt;--output-dir&lt;/code&gt;, snapshot paths, and auto-discovery—resolve against the specified directory instead of the process CWD.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;a class="anchor" href="#architecture"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="context-based-resolution"&gt;Context-Based Resolution&lt;a class="anchor" href="#context-based-resolution"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;--cwd&lt;/code&gt; flag is injected into the Go &lt;code&gt;context.Context&lt;/code&gt; via &lt;code&gt;provider.WithWorkingDirectory()&lt;/code&gt;, avoiding global state mutation. This design:&lt;/p&gt;</description></item><item><title>JSON Schema Migration Decision</title><link>https://oakwood-commons.github.io/scafctl/docs/design/jsonschema-migration-decision/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/jsonschema-migration-decision/</guid><description>&lt;h1 id="provider-schema-migration-custom-schemadefinition--json-schema"&gt;Provider Schema Migration: Custom SchemaDefinition → JSON Schema&lt;a class="anchor" href="#provider-schema-migration-custom-schemadefinition--json-schema"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; Implemented&lt;br&gt;
&lt;strong&gt;Created:&lt;/strong&gt; 2026-02-07&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; (team discussion)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Provider input and output schemas are currently defined using custom types — &lt;code&gt;SchemaDefinition&lt;/code&gt; and &lt;code&gt;PropertyDefinition&lt;/code&gt; — in &lt;code&gt;pkg/provider/provider.go&lt;/code&gt;. These types were purpose-built early in development and serve their role for simple, flat property definitions.&lt;/p&gt;
&lt;p&gt;Meanwhile, the codebase already uses &lt;a href="https://github.com/google/jsonschema-go" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;github.com/google/jsonschema-go&lt;/code&gt;&lt;/a&gt;
 (v0.4.2) for &lt;strong&gt;action result validation&lt;/strong&gt; (&lt;code&gt;Action.ResultSchema&lt;/code&gt;), where it provides full JSON Schema 2020-12 support including &lt;code&gt;$ref&lt;/code&gt;, &lt;code&gt;allOf&lt;/code&gt;/&lt;code&gt;anyOf&lt;/code&gt;/&lt;code&gt;oneOf&lt;/code&gt;, nested objects, and more.&lt;/p&gt;</description></item><item><title>File Conflict Strategies</title><link>https://oakwood-commons.github.io/scafctl/docs/design/file-conflict-strategies/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/file-conflict-strategies/</guid><description>&lt;h1 id="file-conflict-strategies"&gt;File Conflict Strategies&lt;a class="anchor" href="#file-conflict-strategies"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The file provider currently writes files unconditionally — &lt;code&gt;os.WriteFile()&lt;/code&gt; silently overwrites any existing content. This creates problems for scaffolding workflows where solutions are run repeatedly during development: generated files may overwrite user edits, there is no feedback about what changed, and no way to control write behavior per-file.&lt;/p&gt;
&lt;p&gt;This design introduces a &lt;strong&gt;conflict strategy system&lt;/strong&gt; (&lt;code&gt;onConflict&lt;/code&gt;) to the file provider&amp;rsquo;s &lt;code&gt;write&lt;/code&gt; and &lt;code&gt;write-tree&lt;/code&gt; operations. It adds content-based change detection (SHA256 checksums), optional file backups, an append mode with line-level deduplication, and detailed per-file status reporting.&lt;/p&gt;</description></item><item><title>Hugo Guide</title><link>https://oakwood-commons.github.io/scafctl/docs/design/hugo-guide/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/hugo-guide/</guid><description>&lt;h1 id="hugo-guide-for-scafctl"&gt;Hugo Guide for scafctl&lt;a class="anchor" href="#hugo-guide-for-scafctl"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide explains how to set up and use Hugo for the scafctl documentation site.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go 1.21+ installed (Hugo extended is recommended)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="installation"&gt;Installation&lt;a class="anchor" href="#installation"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="option-1-using-homebrew-macos"&gt;Option 1: Using Homebrew (macOS)&lt;a class="anchor" href="#option-1-using-homebrew-macos"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brew install hugo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="option-2-using-go"&gt;Option 2: Using Go&lt;a class="anchor" href="#option-2-using-go"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go install github.com/gohugoio/hugo@latest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="option-3-download-binary"&gt;Option 3: Download Binary&lt;a class="anchor" href="#option-3-download-binary"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Download from &lt;a href="https://github.com/gohugoio/hugo/releases" target="_blank" rel="noopener noreferrer"&gt;Hugo Releases&lt;/a&gt;
 and add to your PATH.&lt;/p&gt;
&lt;h3 id="verify-installation"&gt;Verify Installation&lt;a class="anchor" href="#verify-installation"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hugo version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="initial-setup-one-time"&gt;Initial Setup (One-time)&lt;a class="anchor" href="#initial-setup-one-time"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After cloning the repository, initialize Hugo modules and download the theme:&lt;/p&gt;</description></item><item><title>Resolver Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/resolver-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/resolver-tutorial/</guid><description>&lt;h1 id="resolver-tutorial"&gt;Resolver Tutorial&lt;a class="anchor" href="#resolver-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using scafctl resolvers to dynamically resolve configuration values. You&amp;rsquo;ll learn how to define resolvers, use different providers, handle dependencies, and implement common patterns.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax&lt;/li&gt;
&lt;li&gt;Understanding of environment variables&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#your-first-resolver"&gt;Your First Resolver&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-parameters"&gt;Using Parameters&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#resolver-dependencies"&gt;Resolver Dependencies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#transformations"&gt;Transformations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#validation"&gt;Validation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#conditional-execution"&gt;Conditional Execution&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#error-handling"&gt;Error Handling&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#working-with-http-apis"&gt;Working with HTTP APIs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-patterns"&gt;Common Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="your-first-resolver"&gt;Your First Resolver&lt;a class="anchor" href="#your-first-resolver"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s create a simple solution with one resolver that returns a static value.&lt;/p&gt;</description></item><item><title>Identity Provider</title><link>https://oakwood-commons.github.io/scafctl/docs/design/identity-provider/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/identity-provider/</guid><description>&lt;h1 id="identity-provider"&gt;Identity Provider&lt;a class="anchor" href="#identity-provider"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;strong&gt;identity&lt;/strong&gt; provider exposes authentication identity information from auth handlers. It returns non-sensitive identity data such as claims, authentication status, and identity type. It &lt;strong&gt;never exposes tokens or other secrets&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="operations"&gt;Operations&lt;a class="anchor" href="#operations"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Operation&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Scope Support&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;claims&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Returns identity claims (name, email, subject, etc.)&lt;/td&gt;
 &lt;td&gt;Yes — parse scoped access token JWT&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Returns authentication status, expiry, identity type&lt;/td&gt;
 &lt;td&gt;Yes — return scoped token metadata&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;groups&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Returns Entra group memberships (ObjectIDs)&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;list&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Lists all registered auth handlers&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="inputs"&gt;Inputs&lt;a class="anchor" href="#inputs"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Field&lt;/th&gt;
 &lt;th&gt;Type&lt;/th&gt;
 &lt;th&gt;Required&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;operation&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;string&lt;/td&gt;
 &lt;td&gt;Yes&lt;/td&gt;
 &lt;td&gt;Operation to perform: &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;claims&lt;/code&gt;, &lt;code&gt;groups&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;handler&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;string&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;Auth handler name (e.g., &lt;code&gt;entra&lt;/code&gt;). Defaults to the first authenticated handler.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;scope&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;string&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;OAuth scope for scoped token operations. When set, &lt;code&gt;claims&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; operations mint a token with this scope and return its details instead of stored metadata.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="default-behavior-without-scope"&gt;Default Behavior (without scope)&lt;a class="anchor" href="#default-behavior-without-scope"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When no &lt;code&gt;scope&lt;/code&gt; is provided, the identity provider reads &lt;strong&gt;stored metadata&lt;/strong&gt; from the auth handler&amp;rsquo;s local session. This metadata was extracted from the OIDC ID token JWT at login time:&lt;/p&gt;</description></item><item><title>Run Resolver Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/run-resolver-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/run-resolver-tutorial/</guid><description>&lt;h1 id="run-resolver-tutorial"&gt;Run Resolver Tutorial&lt;a class="anchor" href="#run-resolver-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers the &lt;code&gt;scafctl run resolver&lt;/code&gt; command — a debugging and inspection tool for executing resolvers without running actions. You&amp;rsquo;ll learn how to run all resolvers, target specific resolvers, inspect execution metadata, skip phases, and visualize dependencies.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Familiarity with &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/resolver-tutorial/"&gt;resolvers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A solution file with defined resolvers&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#run-all-resolvers"&gt;Run All Resolvers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#run-specific-resolvers"&gt;Run Specific Resolvers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#execution-metadata"&gt;Execution Metadata&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#skipping-phases"&gt;Skipping Phases&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#dependency-graph"&gt;Dependency Graph&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#snapshots"&gt;Snapshots&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#output-formats"&gt;Output Formats&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#debugging-dependencies"&gt;Debugging Dependencies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#working-with-parameters"&gt;Working with Parameters&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-workflows"&gt;Common Workflows&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;blockquote class='book-hint note'&gt;
&lt;p&gt;&lt;strong&gt;A note on &lt;code&gt;__execution&lt;/code&gt; metadata&lt;/strong&gt;: When using JSON or YAML output, &lt;code&gt;run resolver&lt;/code&gt; automatically includes an &lt;code&gt;__execution&lt;/code&gt; key containing execution metadata (timing, dependency graph, provider stats). Throughout this tutorial, examples use &lt;code&gt;--hide-execution&lt;/code&gt; to keep output focused on resolver values. See &lt;a href="#execution-metadata"&gt;Execution Metadata&lt;/a&gt;
 for details on this feature.&lt;/p&gt;</description></item><item><title>Run Provider Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/run-provider-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/run-provider-tutorial/</guid><description>&lt;h1 id="run-provider-tutorial"&gt;Run Provider Tutorial&lt;a class="anchor" href="#run-provider-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers the &lt;code&gt;scafctl run provider&lt;/code&gt; command — a tool for executing individual providers directly without a solution or resolver file. This is useful for testing, debugging, and exploring providers in isolation.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Familiarity with &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-reference/"&gt;providers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#basic-usage"&gt;Basic Usage&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#passing-inputs"&gt;Passing Inputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#file-based-inputs"&gt;File-Based Inputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#capabilities"&gt;Capabilities&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#dry-run"&gt;Dry Run&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#output-formats"&gt;Output Formats&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#plugin-providers"&gt;Plugin Providers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#discovering-providers"&gt;Discovering Providers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-examples"&gt;Common Examples&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="basic-usage"&gt;Basic Usage&lt;a class="anchor" href="#basic-usage"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;scafctl run provider&lt;/code&gt; command takes a provider name as its first argument. Provider inputs can be passed as positional &lt;code&gt;key=value&lt;/code&gt; arguments or via the traditional &lt;code&gt;--input&lt;/code&gt; flag:&lt;/p&gt;</description></item><item><title>Actions Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/actions-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/actions-tutorial/</guid><description>&lt;h1 id="actions-tutorial"&gt;Actions Tutorial&lt;a class="anchor" href="#actions-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial introduces the Actions feature in scafctl, which enables executing side-effect operations as a declarative action graph.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Actions are the execution phase of a scafctl solution. While &lt;strong&gt;resolvers&lt;/strong&gt; compute and gather data, &lt;strong&gt;actions&lt;/strong&gt; perform work based on that data.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Resolvers&amp;lt;br/&amp;gt;(compute)&amp;#34;] --&amp;gt; B[&amp;#34;Actions&amp;lt;br/&amp;gt;(execute)&amp;#34;] --&amp;gt; C[&amp;#34;Results&amp;lt;br/&amp;gt;(outputs)&amp;#34;]&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Key Principles:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Resolvers compute data, actions perform work&lt;/li&gt;
&lt;li&gt;All resolvers evaluate before any action executes&lt;/li&gt;
&lt;li&gt;Actions can depend on other actions&lt;/li&gt;
&lt;li&gt;Actions can access results from completed actions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-start"&gt;Quick Start&lt;a class="anchor" href="#quick-start"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="1-hello-world"&gt;1. Hello World&lt;a class="anchor" href="#1-hello-world"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The simplest action workflow. Create a file called &lt;code&gt;hello-actions.yaml&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Authentication Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/auth-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/auth-tutorial/</guid><description>&lt;h1 id="authentication-tutorial"&gt;Authentication Tutorial&lt;a class="anchor" href="#authentication-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through setting up and using authentication in scafctl. You&amp;rsquo;ll learn how to authenticate with Microsoft Entra ID, GitHub, and Google Cloud Platform, manage credentials, and use authenticated HTTP requests in your solutions.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;For Entra: Access to a Microsoft Entra ID tenant&lt;/li&gt;
&lt;li&gt;For GitHub: A GitHub account (or GitHub Enterprise Server instance)&lt;/li&gt;
&lt;li&gt;For GCP: A Google Cloud account&lt;/li&gt;
&lt;li&gt;A web browser for completing the device code flow&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#understanding-auth-in-scafctl"&gt;Understanding Auth in scafctl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#logging-in"&gt;Logging In&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#example-output"&gt;Entra Device Code Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#service-principal-authentication-cicd"&gt;Entra Service Principal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#workload-identity-authentication-kubernetes"&gt;Entra Workload Identity&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#github-device-code-flow"&gt;GitHub Device Code Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#github-pat-authentication-cicd"&gt;GitHub PAT Flow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#github-interactive-flow-browser-oauth--pkce"&gt;GitHub Interactive Flow (Browser OAuth + PKCE)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#github-app-installation-token"&gt;GitHub App Installation Token&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gcp-interactive-login-browser-oauth"&gt;GCP Interactive Login&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gcp-service-account-key-authentication-cicd"&gt;GCP Service Account Key&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gcp-workload-identity-federation"&gt;GCP Workload Identity Federation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#gcp-metadata-server-gcegkecloud-run"&gt;GCP Metadata Server&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#checking-auth-status"&gt;Checking Auth Status&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#listing-and-sorting-cached-tokens"&gt;Listing and Sorting Cached Tokens&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-auth-in-http-providers"&gt;Using Auth in HTTP Providers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#getting-tokens-for-debugging"&gt;Getting Tokens for Debugging&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#configuration"&gt;Configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#logging-out"&gt;Logging Out&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#auth-diagnostics"&gt;Auth Diagnostics&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#troubleshooting"&gt;Troubleshooting&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="understanding-auth-in-scafctl"&gt;Understanding Auth in scafctl&lt;a class="anchor" href="#understanding-auth-in-scafctl"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Authentication in scafctl follows these principles:&lt;/p&gt;</description></item><item><title>Docker Credential Helper Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/credential-helper-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/credential-helper-tutorial/</guid><description>&lt;h1 id="docker-credential-helper-tutorial"&gt;Docker Credential Helper Tutorial&lt;a class="anchor" href="#docker-credential-helper-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial shows how to use scafctl as a Docker/Podman credential helper, exposing scafctl&amp;rsquo;s AES-256-GCM encrypted credential store to the container ecosystem.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Docker, Podman, or Buildah installed&lt;/li&gt;
&lt;li&gt;Familiarity with &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/auth-tutorial/"&gt;Authentication Tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#overview"&gt;Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#quick-setup"&gt;Quick Setup&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#manual-setup"&gt;Manual Setup&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#per-registry-configuration"&gt;Per-Registry Configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#how-it-works"&gt;How It Works&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-with-podmanbuildah"&gt;Using with Podman/Buildah&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verification"&gt;Verification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#composing-with-catalog-login"&gt;Composing with catalog login&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#uninstall"&gt;Uninstall&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#troubleshooting"&gt;Troubleshooting&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Docker credential helper protocol allows external programs to manage registry credentials for Docker, Podman, and Buildah. By using scafctl as a credential helper, you get:&lt;/p&gt;</description></item><item><title>GCP Custom OAuth Client Setup</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/gcp-custom-oauth-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/gcp-custom-oauth-tutorial/</guid><description>&lt;h1 id="gcp-custom-oauth-client-setup"&gt;GCP Custom OAuth Client Setup&lt;a class="anchor" href="#gcp-custom-oauth-client-setup"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;By default, &lt;code&gt;scafctl auth login gcp&lt;/code&gt; runs a native browser OAuth flow using Google&amp;rsquo;s well-known ADC client credentials — the same ones used by &lt;code&gt;gcloud auth application-default login&lt;/code&gt;. This works out of the box with &lt;strong&gt;no gcloud installation required&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You may want to set up your own OAuth client if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your organization restricts which OAuth client IDs are allowed&lt;/li&gt;
&lt;li&gt;You need specific OAuth consent screen branding or approval&lt;/li&gt;
&lt;li&gt;You want full control over the client lifecycle and scopes&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class='book-hint caution'&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you were previously seeing &lt;code&gt;invalid_grant - reauth related error (invalid_rapt)&lt;/code&gt; errors, upgrading scafctl to the latest version resolves this — the native browser OAuth flow is no longer affected by gcloud&amp;rsquo;s RAPT token expiry.&lt;/p&gt;</description></item><item><title>Eval Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/eval-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/eval-tutorial/</guid><description>&lt;h1 id="eval-tutorial"&gt;Eval Tutorial&lt;a class="anchor" href="#eval-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers using the &lt;code&gt;scafctl eval&lt;/code&gt; command group to test CEL expressions, render Go templates, and validate solution files — all without running a full solution.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;eval&lt;/code&gt; commands are developer tools for quick iteration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;eval cel&lt;/code&gt;&lt;/strong&gt; — Evaluate CEL expressions with inline or file-based data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;eval template&lt;/code&gt;&lt;/strong&gt; — Render Go templates against JSON/YAML data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For solution file validation, use the separate &lt;strong&gt;&lt;code&gt;scafctl lint&lt;/code&gt;&lt;/strong&gt; command (covered in &lt;a href="#3-validating-solution-files-with-scafctl-lint"&gt;Section 3&lt;/a&gt;
 below).&lt;/p&gt;</description></item><item><title>Linting Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/linting-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/linting-tutorial/</guid><description>&lt;h1 id="linting-tutorial"&gt;Linting Tutorial&lt;a class="anchor" href="#linting-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers using scafctl&amp;rsquo;s lint commands to validate solution files, explore available lint rules, and understand how to fix issues.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl includes a built-in linter that checks solution YAML files for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Schema violations&lt;/strong&gt; — Invalid field names, wrong types, missing required fields&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best practices&lt;/strong&gt; — Missing descriptions, unused resolvers, naming conventions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Correctness&lt;/strong&gt; — Broken resolver references, invalid CEL expressions, circular dependencies&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Solution&amp;lt;br/&amp;gt;YAML&amp;#34;] --&amp;gt; B[&amp;#34;scafctl&amp;lt;br/&amp;gt;lint&amp;#34;] --&amp;gt; C[&amp;#34;Findings&amp;lt;br/&amp;gt;(warnings, errors)&amp;#34;]&lt;/pre&gt;&lt;h2 id="1-linting-a-solution"&gt;1. Linting a Solution&lt;a class="anchor" href="#1-linting-a-solution"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="basic-lint"&gt;Basic Lint&lt;a class="anchor" href="#basic-lint"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="book-tabs"&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-0" checked="checked" /&gt;&lt;label for="tabs-0-0"&gt;Bash&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl lint -f solution.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-1" /&gt;&lt;label for="tabs-0-1"&gt;PowerShell&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl lint &lt;span style="color:#ff7b72;font-weight:bold"&gt;-f&lt;/span&gt; solution.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If your solution file is in a well-known location (&lt;code&gt;solution.yaml&lt;/code&gt;, &lt;code&gt;scafctl.yaml&lt;/code&gt;, etc. in the current directory or &lt;code&gt;scafctl/&lt;/code&gt;/&lt;code&gt;.scafctl/&lt;/code&gt; subdirectories), you can omit &lt;code&gt;-f&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>CEL Expressions Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/cel-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/cel-tutorial/</guid><description>&lt;h1 id="cel-expressions-tutorial"&gt;CEL Expressions Tutorial&lt;a class="anchor" href="#cel-expressions-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers using CEL (Common Expression Language) expressions in scafctl for data transformation, conditional logic, and dynamic configuration.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CEL is used throughout scafctl for dynamic evaluation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resolver transforms&lt;/strong&gt; — Compute derived values from other resolvers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action inputs&lt;/strong&gt; — Build dynamic commands and configurations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conditions&lt;/strong&gt; — Conditionally skip actions with &lt;code&gt;when&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;forEach&lt;/strong&gt; — Generate iteration lists dynamically&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Resolver&amp;lt;br/&amp;gt;Data&amp;#34;] -- &amp;#34;_ namespace&amp;#34; --&amp;gt; B[&amp;#34;CEL&amp;lt;br/&amp;gt;Expression&amp;#34;] --&amp;gt; C[&amp;#34;Result&amp;lt;br/&amp;gt;Value&amp;#34;]&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Key principle:&lt;/strong&gt; In CEL expressions, all resolved values are available under the &lt;code&gt;_&lt;/code&gt; namespace (e.g., &lt;code&gt;_.appName&lt;/code&gt;, &lt;code&gt;_.config.port&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>Go Template LRU Cache</title><link>https://oakwood-commons.github.io/scafctl/docs/design/go-template-cache/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/go-template-cache/</guid><description>&lt;h1 id="go-template-lru-cache"&gt;Go Template LRU Cache&lt;a class="anchor" href="#go-template-lru-cache"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;pkg/gotmpl&lt;/code&gt; package includes a thread-safe LRU (Least Recently Used) cache for compiled Go templates. The cache avoids redundant parsing of identical template content across evaluations, significantly improving performance for solutions that evaluate the same templates repeatedly (e.g., during resolver phases with shared template logic).&lt;/p&gt;
&lt;h2 id="motivation"&gt;Motivation&lt;a class="anchor" href="#motivation"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;text/template.Parse()&lt;/code&gt; is the dominant cost in template evaluation. In large solutions with many resolvers or actions that use similar templates, the same template content is re-parsed on every invocation. The LRU cache stores compiled &lt;code&gt;*template.Template&lt;/code&gt; objects keyed by a SHA-256 hash of their content and configuration, eliminating redundant parse operations while bounding memory usage.&lt;/p&gt;</description></item><item><title>REST API Server Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/api-server-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/api-server-tutorial/</guid><description>&lt;h1 id="rest-api-server"&gt;REST API Server&lt;a class="anchor" href="#rest-api-server"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;scafctl includes a built-in REST API server that exposes all major CLI features as HTTP endpoints. The server uses &lt;a href="https://github.com/go-chi/chi" target="_blank" rel="noopener noreferrer"&gt;chi&lt;/a&gt;
 for routing and &lt;a href="https://huma.rocks" target="_blank" rel="noopener noreferrer"&gt;Huma&lt;/a&gt;
 for OpenAPI-compliant endpoint registration.&lt;/p&gt;
&lt;h2 id="starting-the-server"&gt;Starting the Server&lt;a class="anchor" href="#starting-the-server"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Start with defaults (port 8080, host 127.0.0.1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl serve
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Start on a custom port&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl serve --port &lt;span style="color:#a5d6ff"&gt;9090&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Start with TLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl serve --enable-tls --tls-cert cert.pem --tls-key key.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Custom API version prefix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl serve --api-version v2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="configuration"&gt;Configuration&lt;a class="anchor" href="#configuration"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The server reads its configuration from the &lt;code&gt;apiServer&lt;/code&gt; section of the scafctl config file:&lt;/p&gt;</description></item><item><title>Go Templates Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/go-templates-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/go-templates-tutorial/</guid><description>&lt;h1 id="go-templates-tutorial"&gt;Go Templates Tutorial&lt;a class="anchor" href="#go-templates-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using Go templates in scafctl to generate structured text output like configuration files, documentation, and code scaffolding. You&amp;rsquo;ll start with a simple template and progressively learn conditionals, loops, whitespace control, file-based templates, custom delimiters, and multi-file generation.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax&lt;/li&gt;
&lt;li&gt;Completion of the &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/resolver-tutorial/"&gt;Resolver Tutorial&lt;/a&gt;
 and &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/actions-tutorial/"&gt;Actions Tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#your-first-template"&gt;Your First Template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-conditionals"&gt;Using Conditionals&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#iterating-over-lists"&gt;Iterating Over Lists&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#iterating-over-maps"&gt;Iterating Over Maps&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#controlling-whitespace"&gt;Controlling Whitespace&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#loading-templates-from-files"&gt;Loading Templates from Files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#handling-missing-keys"&gt;Handling Missing Keys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#injecting-additional-data"&gt;Injecting Additional Data&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-custom-delimiters"&gt;Using Custom Delimiters&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-tmpl-for-dynamic-inputs"&gt;Using &lt;code&gt;tmpl&lt;/code&gt; for Dynamic Inputs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#generating-multiple-files-with-foreach"&gt;Generating Multiple Files with ForEach&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#rendering-template-directories"&gt;Rendering Template Directories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#putting-it-all-together-readme-generator"&gt;Putting It All Together: README Generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-sprig-functions"&gt;Using Sprig Functions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#converting-data-to-hcl-with-tohcl"&gt;Converting Data to HCL with toHcl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#serializing-and-parsing-yaml-with-toyaml--fromyaml"&gt;Serializing and Parsing YAML with toYaml / fromYaml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#dns-safe-strings-with-slugify--todnsstring"&gt;DNS-Safe Strings with slugify / toDnsString&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#filtering-lists-with-where--selectfield"&gt;Filtering Lists with where / selectField&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#inline-cel-with-cel"&gt;Inline CEL with cel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#debugging-template-type-errors"&gt;Debugging Template Type Errors&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#discovering-available-functions"&gt;Discovering Available Functions&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl supports Go templates in two ways:&lt;/p&gt;</description></item><item><title>Catalog Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/catalog-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/catalog-tutorial/</guid><description>&lt;h1 id="catalog-tutorial"&gt;Catalog Tutorial&lt;a class="anchor" href="#catalog-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using scafctl&amp;rsquo;s local catalog to build, version, inspect, export, and share solutions. You&amp;rsquo;ll start by building your first solution into the catalog and progressively work through versioning, cleanup, air-gapped transfers, remote registries, tagging, and advanced bundling with file dependencies.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax&lt;/li&gt;
&lt;li&gt;Completion of the &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/resolver-tutorial/"&gt;Resolver Tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#building-your-first-solution"&gt;Building Your First Solution&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#running-from-the-catalog"&gt;Running from the Catalog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#listing-and-inspecting"&gt;Listing and Inspecting&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#managing-multiple-versions"&gt;Managing Multiple Versions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#deleting-and-pruning"&gt;Deleting and Pruning&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#exporting-and-importing"&gt;Exporting and Importing&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#tagging-artifacts"&gt;Tagging Artifacts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#remote-registries"&gt;Remote Registries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#bundling-file-dependencies"&gt;Bundling File Dependencies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#verifying-and-extracting-bundles"&gt;Verifying and Extracting Bundles&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#comparing-bundle-versions"&gt;Comparing Bundle Versions&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="building-your-first-solution"&gt;Building Your First Solution&lt;a class="anchor" href="#building-your-first-solution"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s build a simple solution and store it in the local catalog so you can run it by name from anywhere.&lt;/p&gt;</description></item><item><title>MCP Server Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/mcp-server-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/mcp-server-tutorial/</guid><description>&lt;h1 id="mcp-server-tutorial"&gt;MCP Server Tutorial&lt;a class="anchor" href="#mcp-server-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through setting up scafctl&amp;rsquo;s Model Context Protocol (MCP) server so that AI agents — GitHub Copilot, Claude, Cursor, Windsurf, and others — can discover and invoke scafctl tools programmatically.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and on your &lt;code&gt;$PATH&lt;/code&gt; (&lt;code&gt;scafctl version&lt;/code&gt; should work)&lt;/li&gt;
&lt;li&gt;An MCP-compatible AI client (VS Code with Copilot, Claude Desktop, Cursor, or Windsurf)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-is-the-mcp-server"&gt;What Is the MCP Server?&lt;a class="anchor" href="#what-is-the-mcp-server"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The MCP server is a &lt;strong&gt;local process&lt;/strong&gt; that translates between the AI agent&amp;rsquo;s JSON-RPC protocol and scafctl&amp;rsquo;s Go library functions. When an AI agent decides to use a tool (e.g., &amp;ldquo;lint this solution&amp;rdquo;), it sends a structured request to the MCP server, which calls the same code that the CLI commands use and returns structured JSON results.&lt;/p&gt;</description></item><item><title>Security Hardening</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/security-hardening/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/security-hardening/</guid><description>&lt;h1 id="security-hardening-guide"&gt;Security Hardening Guide&lt;a class="anchor" href="#security-hardening-guide"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide covers scafctl&amp;rsquo;s built-in security protections and how to configure them for production environments.&lt;/p&gt;
&lt;h2 id="http-provider-security"&gt;HTTP Provider Security&lt;a class="anchor" href="#http-provider-security"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="response-body-size-limits"&gt;Response Body Size Limits&lt;a class="anchor" href="#response-body-size-limits"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The HTTP provider limits the amount of data it will read from any single response to prevent denial-of-service via unbounded responses. The default limit is &lt;strong&gt;100 MB&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# config.yaml — adjust the limit&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;httpClient&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;maxResponseBodySize&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;104857600&lt;/span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# 100 MB (default)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The limit applies to both direct requests &lt;strong&gt;and&lt;/strong&gt; each page in paginated requests. If a response exceeds the limit, the provider returns an error rather than consuming unbounded memory.&lt;/p&gt;</description></item><item><title>REST API Server Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/serve-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/serve-tutorial/</guid><description>&lt;h1 id="rest-api-server-tutorial"&gt;REST API Server Tutorial&lt;a class="anchor" href="#rest-api-server-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through starting scafctl&amp;rsquo;s REST API server and interacting with its endpoints. The API mirrors all major CLI features — solutions, providers, catalogs, schemas, eval, config, and more — over HTTP with OpenAPI documentation.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and on your &lt;code&gt;$PATH&lt;/code&gt; (&lt;code&gt;scafctl version&lt;/code&gt; should work)&lt;/li&gt;
&lt;li&gt;curl or any HTTP client for testing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-start"&gt;Quick Start&lt;a class="anchor" href="#quick-start"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="start-the-server"&gt;Start the Server&lt;a class="anchor" href="#start-the-server"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl serve&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The server starts on &lt;code&gt;http://localhost:8080&lt;/code&gt; by default.&lt;/p&gt;</description></item><item><title>Validation Patterns Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/validation-patterns-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/validation-patterns-tutorial/</guid><description>&lt;h1 id="validation-patterns-tutorial"&gt;Validation Patterns Tutorial&lt;a class="anchor" href="#validation-patterns-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Learn how to validate resolver outputs, enforce constraints on inputs, and use schema validation to catch issues early.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl offers multiple validation layers that work together to ensure configuration correctness:&lt;/p&gt;
&lt;pre class="mermaid"&gt;block-beta
 columns 4
 block:top:4
 A[&amp;#34;Solution YAML&amp;#34;]
 end
 B[&amp;#34;Lint&amp;lt;br/&amp;gt;Rules&amp;#34;] C[&amp;#34;Schema&amp;lt;br/&amp;gt;Helper Tags&amp;#34;] D[&amp;#34;Validate&amp;lt;br/&amp;gt;Provider&amp;#34;] E[&amp;#34;Result&amp;lt;br/&amp;gt;Schema&amp;#34;]
 block:bottom:4
 F[&amp;#34;Runtime Validation (CEL + Regex)&amp;#34;]
 end&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Schema helper tags&lt;/strong&gt; — provider-level input constraints (type, length, pattern, enum)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation provider&lt;/strong&gt; — runtime regex and CEL-based checks on resolver values&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Result schemas&lt;/strong&gt; — JSON Schema validation of action outputs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lint rules&lt;/strong&gt; — static analysis at &lt;code&gt;scafctl lint&lt;/code&gt; time&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="1-schema-level-validation-with-provider-inputs"&gt;1. Schema-Level Validation with Provider Inputs&lt;a class="anchor" href="#1-schema-level-validation-with-provider-inputs"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Provider schemas use JSON Schema constraints to reject invalid input before execution.&lt;/p&gt;</description></item><item><title>Provider Output Shapes</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-output-shapes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-output-shapes/</guid><description>&lt;h1 id="provider-output-shapes"&gt;Provider Output Shapes&lt;a class="anchor" href="#provider-output-shapes"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Quick reference for what each built-in provider returns in resolver output — the data shape you can access via &lt;code&gt;_.resolverName&lt;/code&gt; in CEL expressions and Go templates.&lt;/p&gt;
&lt;h2 id="how-provider-output-works"&gt;How Provider Output Works&lt;a class="anchor" href="#how-provider-output-works"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a resolver uses a provider, the resolved value becomes accessible to other resolvers. The &lt;strong&gt;output shape&lt;/strong&gt; determines what fields are available:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Resolver: api_data&amp;lt;br/&amp;gt;provider: http&amp;lt;br/&amp;gt;output: body, statusCode, headers&amp;#34;] --&amp;gt; B[&amp;#34;Resolver: summary&amp;lt;br/&amp;gt;expr: _.api_data&amp;lt;br/&amp;gt;.body.items | size()&amp;#34;]&lt;/pre&gt;&lt;blockquote class='book-hint note'&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Use the MCP tool &lt;code&gt;get_provider_output_shape&lt;/code&gt; to query output schemas programmatically, or &lt;code&gt;get_provider_schema&lt;/code&gt; for full provider documentation.&lt;/p&gt;</description></item><item><title>Message Provider Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/message-provider-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/message-provider-tutorial/</guid><description>&lt;h1 id="message-provider-tutorial"&gt;Message Provider Tutorial&lt;a class="anchor" href="#message-provider-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers using the &lt;strong&gt;message&lt;/strong&gt; provider for rich terminal output during solution execution — styled messages with icons, colors, and dynamic interpolation via &lt;code&gt;tmpl:&lt;/code&gt;/&lt;code&gt;expr:&lt;/code&gt; ValueRefs.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The message provider replaces awkward &lt;code&gt;exec&lt;/code&gt; + &lt;code&gt;echo&lt;/code&gt; patterns with first-class terminal messaging that integrates with scafctl&amp;rsquo;s &lt;code&gt;--quiet&lt;/code&gt;, &lt;code&gt;--no-color&lt;/code&gt;, and &lt;code&gt;--dry-run&lt;/code&gt; flags.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Resolver&amp;lt;br/&amp;gt;Data&amp;#34;] --&amp;gt; B[&amp;#34;Message&amp;lt;br/&amp;gt;Provider&amp;#34;]
 B -- &amp;#34;styled output&amp;#34; --&amp;gt; C[&amp;#34;Terminal&amp;lt;br/&amp;gt;(stdout/stderr)&amp;#34;]
 B -- &amp;#34;data&amp;#34; --&amp;gt; D[&amp;#34;Output&amp;lt;br/&amp;gt;{success, message}&amp;#34;]&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Key features:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Built-in message types: &lt;code&gt;success&lt;/code&gt;, &lt;code&gt;warning&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;info&lt;/code&gt;, &lt;code&gt;debug&lt;/code&gt;, &lt;code&gt;plain&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Custom styling: colors (hex or named), bold, italic, custom icons/emoji&lt;/li&gt;
&lt;li&gt;Contextual labels: dimmed &lt;code&gt;[label]&lt;/code&gt; prefixes for step tracking (e.g., &lt;code&gt;[step 2/5]&lt;/code&gt;, &lt;code&gt;[deploy]&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Dynamic interpolation via framework &lt;code&gt;tmpl:&lt;/code&gt; and &lt;code&gt;expr:&lt;/code&gt; ValueRefs (with automatic dependency detection)&lt;/li&gt;
&lt;li&gt;Respects &lt;code&gt;--quiet&lt;/code&gt; flag (messages suppressed in quiet mode)&lt;/li&gt;
&lt;li&gt;Trailing newline control via the &lt;code&gt;newline&lt;/code&gt; field&lt;/li&gt;
&lt;li&gt;Dry-run awareness via &lt;code&gt;--dry-run&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="quick-start"&gt;Quick Start&lt;a class="anchor" href="#quick-start"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="step-1-create-the-solution-file"&gt;Step 1: Create the Solution File&lt;a class="anchor" href="#step-1-create-the-solution-file"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a file called &lt;code&gt;message-basics.yaml&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Snapshots Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/snapshots-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/snapshots-tutorial/</guid><description>&lt;h1 id="snapshots-tutorial"&gt;Snapshots Tutorial&lt;a class="anchor" href="#snapshots-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers using execution snapshots for debugging, testing, and comparing solution runs.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snapshots capture the state of resolver execution — values, timing, status, errors, and parameters — as a JSON file. They&amp;rsquo;re useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Debugging&lt;/strong&gt; — Inspect what every resolver produced&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing&lt;/strong&gt; — Compare before/after to catch regressions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auditing&lt;/strong&gt; — Record what ran and what it produced&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sharing&lt;/strong&gt; — Send a snapshot to a teammate for review (with redaction for secrets)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;render&amp;lt;br/&amp;gt;solution&amp;#34;] --&amp;gt; B[&amp;#34;Snapshot&amp;lt;br/&amp;gt;(JSON)&amp;#34;] --&amp;gt; C[&amp;#34;show / diff&amp;lt;br/&amp;gt;commands&amp;#34;]&lt;/pre&gt;&lt;h2 id="when-to-use-snapshots"&gt;When to Use Snapshots&lt;a class="anchor" href="#when-to-use-snapshots"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Snapshots are &lt;strong&gt;flag-triggered&lt;/strong&gt; (&lt;code&gt;--snapshot&lt;/code&gt;), never automatically created. Here are the real-world scenarios where they provide value:&lt;/p&gt;</description></item><item><title>Functional Testing</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/functional-testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/functional-testing/</guid><description>&lt;h1 id="functional-testing"&gt;Functional Testing&lt;a class="anchor" href="#functional-testing"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Functional testing lets you define automated tests for your solutions directly in the solution YAML.
Tests execute scafctl commands in isolated sandboxes and validate output using assertions, snapshots,
and CEL expressions.&lt;/p&gt;
&lt;p&gt;This tutorial walks through every feature of &lt;code&gt;scafctl test functional&lt;/code&gt; — from basic tests to
advanced CI integration.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="writing-your-first-test"&gt;Writing Your First Test&lt;a class="anchor" href="#writing-your-first-test"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Add a &lt;code&gt;testing&lt;/code&gt; section to your solution&amp;rsquo;s &lt;code&gt;spec&lt;/code&gt;. Create a file called &lt;code&gt;solution.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;apiVersion&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;scafctl.io/v1&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;kind&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;Solution&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;metadata&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;name&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;my-solution&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7ee787"&gt;spec&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;resolvers&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;greeting&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;description&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;A greeting message&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;resolve&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;with&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;- &lt;span style="color:#7ee787"&gt;provider&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;static&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;inputs&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;value&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;Hello, World!&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;testing&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;cases&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;render-basic&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;description&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;Verify solution renders successfully&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;command&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;[&lt;span style="color:#a5d6ff"&gt;render, solution]&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#7ee787"&gt;assertions&lt;/span&gt;:&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;- &lt;span style="color:#7ee787"&gt;expression&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;__exitCode == 0&lt;/span&gt;&lt;span style="color:#6e7681"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6e7681"&gt; &lt;/span&gt;- &lt;span style="color:#7ee787"&gt;contains&lt;/span&gt;:&lt;span style="color:#6e7681"&gt; &lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;greeting&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run the test:&lt;/p&gt;</description></item><item><title>Solution Diff Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/soldiff-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/soldiff-tutorial/</guid><description>&lt;p&gt;This tutorial covers comparing two solution files structurally to understand what changed between versions. The &lt;code&gt;soldiff&lt;/code&gt; package detects additions, removals, and modifications across metadata, resolvers, actions, and testing sections.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Solution diffing answers the question: &lt;strong&gt;&amp;ldquo;What structurally changed between two versions of a solution?&amp;rdquo;&lt;/strong&gt; Unlike &lt;code&gt;git diff&lt;/code&gt; which shows text changes, &lt;code&gt;soldiff&lt;/code&gt; understands the solution schema and reports meaningful structural differences.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌──────────────┐ ┌──────────────┐ ┌──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ solution-v1 │ │ soldiff │ │ Result │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ .yaml │ ──► │ .Compare() │ ──► │ (changes, │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ │ │ │ │ summary) │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ solution-v2 │ ──► │ │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ .yaml │ │ │ │ │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└──────────────┘ └──────────────┘ └──────────────┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="when-to-use-solution-diff"&gt;When to Use Solution Diff&lt;a class="anchor" href="#when-to-use-solution-diff"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Use Case&lt;/th&gt;
 &lt;th&gt;Scenario&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Code review&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Review structural impact of solution YAML changes before merging&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Configuration drift&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Detect when a deployed solution has drifted from the expected baseline&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Refactoring validation&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Confirm a refactor didn&amp;rsquo;t accidentally add/remove resolvers or actions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Version comparison&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Compare v1 and v2 of a solution to document what changed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="cli-usage"&gt;CLI Usage&lt;a class="anchor" href="#cli-usage"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="basic-comparison"&gt;Basic Comparison&lt;a class="anchor" href="#basic-comparison"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="book-tabs"&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-0" checked="checked" /&gt;&lt;label for="tabs-0-0"&gt;Bash&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl solution diff -f solution-v1.yaml -f solution-v2.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-1" /&gt;&lt;label for="tabs-0-1"&gt;PowerShell&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl solution diff &lt;span style="color:#ff7b72;font-weight:bold"&gt;-f&lt;/span&gt; solution-v1.&lt;span style="color:#79c0ff"&gt;yaml&lt;/span&gt; &lt;span style="color:#ff7b72;font-weight:bold"&gt;-f&lt;/span&gt; solution-v2.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;</description></item><item><title>Dry-Run Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/dryrun-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/dryrun-tutorial/</guid><description>&lt;h1 id="dry-run-tutorial"&gt;Dry-Run Tutorial&lt;a class="anchor" href="#dry-run-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers using &lt;code&gt;--dry-run&lt;/code&gt; to preview what a solution execution would do without performing any side effects.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dry-run mode resolves all values and builds an action execution plan, but never executes actions. This gives you a complete picture of what &lt;em&gt;would&lt;/em&gt; happen:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Solution&amp;lt;br/&amp;gt;(.yaml)&amp;#34;] --&amp;gt; B[&amp;#34;Dry-Run Generator&amp;lt;br/&amp;gt;⚠️ No side effects!&amp;#34;] --&amp;gt; C[&amp;#34;Report&amp;lt;br/&amp;gt;(resolvers, actions, phases)&amp;#34;]&lt;/pre&gt;&lt;h2 id="when-to-use-dry-run"&gt;When to Use Dry-Run&lt;a class="anchor" href="#when-to-use-dry-run"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Use Case&lt;/th&gt;
 &lt;th&gt;Scenario&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Pre-flight check&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Verify all resolvers produce expected values before executing actions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Action plan review&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;See the execution order, phases, and dependencies before running&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;CI validation&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Assert resolver outputs in a pipeline without side effects&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Debugging&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Understand why a solution behaves unexpectedly by inspecting resolved values&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Documentation&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Generate a report of what a solution does for review or audit&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="cli-usage"&gt;CLI Usage&lt;a class="anchor" href="#cli-usage"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="dry-run-a-full-solution"&gt;Dry-Run a Full Solution&lt;a class="anchor" href="#dry-run-a-full-solution"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="book-tabs"&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-0" checked="checked" /&gt;&lt;label for="tabs-0-0"&gt;Bash&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run solution -f solution.yaml --dry-run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-1" /&gt;&lt;label for="tabs-0-1"&gt;PowerShell&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run solution &lt;span style="color:#ff7b72;font-weight:bold"&gt;-f&lt;/span&gt; solution.&lt;span style="color:#79c0ff"&gt;yaml&lt;/span&gt; --dry-run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This resolves all values and shows the action plan without executing any actions.&lt;/p&gt;</description></item><item><title>Output Directory Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/output-dir-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/output-dir-tutorial/</guid><description>&lt;h1 id="output-directory-tutorial"&gt;Output Directory Tutorial&lt;a class="anchor" href="#output-directory-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using the &lt;code&gt;--output-dir&lt;/code&gt; flag to redirect action output to a specific directory. You&amp;rsquo;ll learn the phase-based directory model, how resolvers and actions differ in path handling, and how to reference the original working directory with &lt;code&gt;__cwd&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax and solution files&lt;/li&gt;
&lt;li&gt;Completion of the &lt;a href="../getting-started/"&gt;Getting Started&lt;/a&gt;
 tutorial&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#overview"&gt;Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-based-directory-model"&gt;Phase-Based Directory Model&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#basic-usage"&gt;Basic Usage&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-__cwd-for-original-directory-access"&gt;Using &lt;code&gt;__cwd&lt;/code&gt; for Original Directory Access&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#combining-with-dry-run"&gt;Combining with Dry-Run&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#per-provider-usage"&gt;Per-Provider Usage&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#default-via-configuration"&gt;Default via Configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#absolute-paths-are-never-rewritten"&gt;Absolute Paths Are Never Rewritten&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#affected-providers"&gt;Affected Providers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-patterns"&gt;Common Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, actions resolve relative paths against the current working directory (CWD). The &lt;code&gt;--output-dir&lt;/code&gt; flag changes this so actions write to a designated output directory instead, while resolvers continue reading from CWD.&lt;/p&gt;</description></item><item><title>Auto-Discovery Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/auto-discovery-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/auto-discovery-tutorial/</guid><description>&lt;h1 id="auto-discovery-tutorial"&gt;Auto-Discovery Tutorial&lt;a class="anchor" href="#auto-discovery-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial explains how scafctl automatically discovers solution files, making the &lt;code&gt;-f&lt;/code&gt; flag optional for most commands.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax and solution files&lt;/li&gt;
&lt;li&gt;Completion of the &lt;a href="../getting-started/"&gt;Getting Started&lt;/a&gt;
 tutorial&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#overview"&gt;Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#how-auto-discovery-works"&gt;How Auto-Discovery Works&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#search-order"&gt;Search Order&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#supported-commands"&gt;Supported Commands&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#examples"&gt;Examples&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#interaction-with---cwd"&gt;Interaction with &lt;code&gt;--cwd&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#when-auto-discovery-fails"&gt;When Auto-Discovery Fails&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#best-practices"&gt;Best Practices&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many scafctl commands accept a &lt;code&gt;-f&lt;/code&gt; / &lt;code&gt;--file&lt;/code&gt; flag to specify the solution file path. When this flag is omitted, scafctl searches the current directory (or the &lt;code&gt;--cwd&lt;/code&gt; target) for a solution file using a well-defined search order.&lt;/p&gt;</description></item><item><title>Configuration Management</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/config-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/config-tutorial/</guid><description>&lt;h1 id="configuration-management-tutorial"&gt;Configuration Management Tutorial&lt;a class="anchor" href="#configuration-management-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers managing scafctl&amp;rsquo;s application configuration using the &lt;code&gt;config&lt;/code&gt; CLI commands.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl uses a YAML configuration file to control application behavior including logging, HTTP client settings, resolver timeouts, catalog locations, and more.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Command&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;config init&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Create config file&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;config view&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;View current config&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;config get/set&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Read/write values&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;config validate&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Validate config&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;config schema&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;View JSON schema&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;config paths&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Show XDG paths&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="quick-start"&gt;Quick Start&lt;a class="anchor" href="#quick-start"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="1-initialize-configuration"&gt;1. Initialize Configuration&lt;a class="anchor" href="#1-initialize-configuration"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a new config file:&lt;/p&gt;</description></item><item><title>File Provider Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/file-provider-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/file-provider-tutorial/</guid><description>&lt;h1 id="file-provider-tutorial"&gt;File Provider Tutorial&lt;a class="anchor" href="#file-provider-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using the &lt;code&gt;file&lt;/code&gt; provider to read, write, check existence, delete files, and write multiple files at once with &lt;code&gt;write-tree&lt;/code&gt;. You&amp;rsquo;ll learn how to use conflict strategies, backups, append with deduplication, and dry-run mode.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax and solution files&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#reading-files"&gt;Reading Files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#writing-files"&gt;Writing Files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#checking-file-existence"&gt;Checking File Existence&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#deleting-files"&gt;Deleting Files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#writing-multiple-files-write-tree"&gt;Writing Multiple Files (write-tree)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#conflict-strategies"&gt;Conflict Strategies&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#append-with-deduplication"&gt;Append with Deduplication&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#backups"&gt;Backups&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#per-entry-overrides-in-write-tree"&gt;Per-Entry Overrides in write-tree&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#cli-flags"&gt;CLI Flags&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#dry-run-mode"&gt;Dry-Run Mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-patterns"&gt;Common Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="reading-files"&gt;Reading Files&lt;a class="anchor" href="#reading-files"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;read&lt;/code&gt; operation reads the contents of a file. Create a file called &lt;code&gt;read-file.yaml&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Exec Provider Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/exec-provider-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/exec-provider-tutorial/</guid><description>&lt;h1 id="exec-provider-tutorial"&gt;Exec Provider Tutorial&lt;a class="anchor" href="#exec-provider-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using the &lt;code&gt;exec&lt;/code&gt; provider to run shell commands cross-platform. You&amp;rsquo;ll learn how the embedded POSIX shell works, how to use pipes, environment variables, timeouts, and when to use external shells like bash or PowerShell.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax and solution files&lt;/li&gt;
&lt;li&gt;(Optional) &lt;code&gt;bash&lt;/code&gt; and/or &lt;code&gt;pwsh&lt;/code&gt; installed for external shell examples&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#how-it-works"&gt;How It Works&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#running-simple-commands"&gt;Running Simple Commands&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#pipes-and-shell-features"&gt;Pipes and Shell Features&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#arguments"&gt;Arguments&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#environment-variables"&gt;Environment Variables&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#working-directory"&gt;Working Directory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#standard-input"&gt;Standard Input&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#timeouts"&gt;Timeouts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#shell-types"&gt;Shell Types&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#cross-platform-patterns"&gt;Cross-Platform Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#error-handling"&gt;Error Handling&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-patterns"&gt;Common Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="how-it-works"&gt;How It Works&lt;a class="anchor" href="#how-it-works"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The exec provider uses an &lt;strong&gt;embedded POSIX shell&lt;/strong&gt; (powered by &lt;a href="https://github.com/mvdan/sh" target="_blank" rel="noopener noreferrer"&gt;mvdan.cc/sh&lt;/a&gt;
) as its default execution engine. This means:&lt;/p&gt;</description></item><item><title>Directory Provider Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/directory-provider-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/directory-provider-tutorial/</guid><description>&lt;h1 id="directory-provider-tutorial"&gt;Directory Provider Tutorial&lt;a class="anchor" href="#directory-provider-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using the &lt;code&gt;directory&lt;/code&gt; provider to list, scan, create, remove, and copy directories. You&amp;rsquo;ll learn how to use filtering, recursive traversal, content reading, and checksums for filesystem-oriented workflows.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax and solution files&lt;/li&gt;
&lt;li&gt;A local directory with some files to experiment with&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#listing-directory-contents"&gt;Listing Directory Contents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#recursive-traversal"&gt;Recursive Traversal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#filtering-with-globs-and-regex"&gt;Filtering with Globs and Regex&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#reading-file-contents"&gt;Reading File Contents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#computing-checksums"&gt;Computing Checksums&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#creating-directories"&gt;Creating Directories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#removing-directories"&gt;Removing Directories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#copying-directories"&gt;Copying Directories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#dry-run-mode"&gt;Dry Run Mode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-patterns"&gt;Common Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="listing-directory-contents"&gt;Listing Directory Contents&lt;a class="anchor" href="#listing-directory-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simplest use of the directory provider is listing files and directories in a given path. Create a file called &lt;code&gt;list-dir.yaml&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Logging &amp; Debugging</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/logging-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/logging-tutorial/</guid><description>&lt;h1 id="logging--debugging-tutorial"&gt;Logging &amp;amp; Debugging Tutorial&lt;a class="anchor" href="#logging--debugging-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers controlling scafctl&amp;rsquo;s log output — verbosity, format, destination, and environment variable overrides.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By default, scafctl produces &lt;strong&gt;no structured log output&lt;/strong&gt;. Only styled user messages (errors, warnings, success indicators) are shown. This keeps the CLI clean for human users and pipe-friendly for scripts.&lt;/p&gt;
&lt;p&gt;When you need to see what&amp;rsquo;s happening under the hood — debugging a solution, reporting a bug, or feeding structured logs to a log aggregation system — scafctl gives you full control over log verbosity, format, and destination.&lt;/p&gt;</description></item><item><title>HCL Provider Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/hcl-provider-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/hcl-provider-tutorial/</guid><description>&lt;h1 id="hcl-provider-tutorial"&gt;HCL Provider Tutorial&lt;a class="anchor" href="#hcl-provider-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through using the &lt;code&gt;hcl&lt;/code&gt; provider to parse Terraform and OpenTofu configuration files. You&amp;rsquo;ll learn how to extract variables, resources, modules, outputs, and other block types from HCL content.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with YAML syntax and solution files&lt;/li&gt;
&lt;li&gt;Basic understanding of Terraform/OpenTofu configuration syntax&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#parsing-inline-hcl-content"&gt;Parsing Inline HCL Content&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#parsing-hcl-files"&gt;Parsing HCL Files&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#multi-file-and-directory-support"&gt;Multi-File and Directory Support&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#extracting-variables"&gt;Extracting Variables&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#extracting-resources"&gt;Extracting Resources&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#working-with-modules"&gt;Working with Modules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#terraform-block-extraction"&gt;Terraform Block Extraction&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#combining-with-cel-expressions"&gt;Combining with CEL Expressions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#transform-capability"&gt;Transform Capability&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#expression-handling"&gt;Expression Handling&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#common-patterns"&gt;Common Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#formatting-hcl-content"&gt;Formatting HCL Content&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#validating-hcl-syntax"&gt;Validating HCL Syntax&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#generating-hcl-from-structured-data"&gt;Generating HCL from Structured Data&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#generating-terraform-json-tfjson"&gt;Generating Terraform JSON (&lt;code&gt;.tf.json&lt;/code&gt;)&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="parsing-inline-hcl-content"&gt;Parsing Inline HCL Content&lt;a class="anchor" href="#parsing-inline-hcl-content"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simplest way to use the HCL provider is with inline content. Create a file called &lt;code&gt;parse-hcl.yaml&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Telemetry (Traces, Metrics, Logs)</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/telemetry-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/telemetry-tutorial/</guid><description>&lt;h1 id="telemetry-tutorial"&gt;Telemetry Tutorial&lt;a class="anchor" href="#telemetry-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;scafctl emits &lt;strong&gt;all three OpenTelemetry signals&lt;/strong&gt; — logs, traces, and metrics.
By default, telemetry is silent (noop providers). When you point scafctl at an
OTLP endpoint every signal is exported for backend analysis.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Signal&lt;/th&gt;
 &lt;th&gt;Default output&lt;/th&gt;
 &lt;th&gt;With &lt;code&gt;--otel-endpoint&lt;/code&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Logs&lt;/td&gt;
 &lt;td&gt;slog text/JSON → stderr (via &lt;code&gt;--log-level&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;Also batched via OTLP gRPC&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Traces&lt;/td&gt;
 &lt;td&gt;Disabled (noop)&lt;/td&gt;
 &lt;td&gt;Exported via OTLP gRPC&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Metrics&lt;/td&gt;
 &lt;td&gt;Prometheus &lt;code&gt;/metrics&lt;/code&gt; (MCP server)&lt;/td&gt;
 &lt;td&gt;Also pushed via OTLP gRPC&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="configuration"&gt;Configuration&lt;a class="anchor" href="#configuration"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="flags-per-invocation"&gt;Flags (per-invocation)&lt;a class="anchor" href="#flags-per-invocation"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="book-tabs"&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-0" checked="checked" /&gt;&lt;label for="tabs-0-0"&gt;Bash&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Point at a local OTel Collector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run solution -f solution.yaml &lt;span style="color:#79c0ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --otel-endpoint localhost:4317 &lt;span style="color:#79c0ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --otel-insecure &lt;span style="color:#8b949e;font-style:italic"&gt;# disable TLS (development only)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Override with environment variable instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#79c0ff"&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span style="color:#ff7b72;font-weight:bold"&gt;=&lt;/span&gt;localhost:4317 &lt;span style="color:#79c0ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; scafctl run solution -f solution.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;input type="radio" class="toggle" name="tabs-0" id="tabs-0-1" /&gt;&lt;label for="tabs-0-1"&gt;PowerShell&lt;/label&gt;&lt;div class="book-tabs-content markdown-inner"&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Point at a local OTel Collector&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run solution &lt;span style="color:#ff7b72;font-weight:bold"&gt;-f&lt;/span&gt; solution.&lt;span style="color:#79c0ff"&gt;yaml&lt;/span&gt; `
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --otel-endpoint localhost&lt;span style="color:#f85149"&gt;:&lt;/span&gt;&lt;span style="color:#a5d6ff"&gt;4317&lt;/span&gt; `
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --otel-insecure &lt;span style="color:#8b949e;font-style:italic"&gt;# disable TLS (development only)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#8b949e;font-style:italic"&gt;# Override with environment variable instead&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#79c0ff"&gt;$env:OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt; = &lt;span style="color:#a5d6ff"&gt;&amp;#39;localhost:4317&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;scafctl run solution &lt;span style="color:#ff7b72;font-weight:bold"&gt;-f&lt;/span&gt; solution.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Flag&lt;/th&gt;
 &lt;th&gt;Env override&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--otel-endpoint&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(none)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;OTLP gRPC endpoint. When unset, tracing is disabled (noop).&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--otel-insecure&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(none)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Skip TLS verification. Use in local dev only.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="signals-in-detail"&gt;Signals in Detail&lt;a class="anchor" href="#signals-in-detail"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="logs"&gt;Logs&lt;a class="anchor" href="#logs"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Logs use the &lt;code&gt;go-logr/logr&lt;/code&gt; interface throughout the codebase. The underlying
sink is a &lt;code&gt;multiSink&lt;/code&gt; that fans out to:&lt;/p&gt;</description></item><item><title>Template Directory Rendering</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/template-directory-rendering/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/template-directory-rendering/</guid><description>&lt;h1 id="template-directory-rendering-tutorial"&gt;Template Directory Rendering Tutorial&lt;a class="anchor" href="#template-directory-rendering-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks you through the recommended pattern for rendering a directory
tree of Go templates into output files while preserving the directory structure.
You&amp;rsquo;ll learn how to combine three providers — &lt;code&gt;directory&lt;/code&gt;, &lt;code&gt;go-template&lt;/code&gt;, and
&lt;code&gt;file&lt;/code&gt; — in a single solution to scaffold entire projects from templates.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl installed and available in your PATH&lt;/li&gt;
&lt;li&gt;Basic familiarity with solution files and Go template syntax&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#overview"&gt;Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#setting-up-templates"&gt;Setting Up Templates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#reading-templates-with-the-directory-provider"&gt;Reading Templates with the Directory Provider&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#batch-rendering-with-render-tree"&gt;Batch Rendering with render-tree&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#writing-files-with-write-tree"&gt;Writing Files with write-tree&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#path-transformation-with-outputpath"&gt;Path Transformation with outputPath&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#putting-it-all-together"&gt;Putting It All Together&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#advanced-patterns"&gt;Advanced Patterns&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A common scaffolding task is:&lt;/p&gt;</description></item><item><title>Implementation Gaps</title><link>https://oakwood-commons.github.io/scafctl/docs/design/implementation-gaps/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/implementation-gaps/</guid><description>&lt;h1 id="implementation-gaps"&gt;Implementation Gaps&lt;a class="anchor" href="#implementation-gaps"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote class='book-hint '&gt;
&lt;p&gt;&lt;strong&gt;Generated:&lt;/strong&gt; 2026-02-25&lt;/p&gt;
&lt;p&gt;This document tracks features described in design documents that are &lt;strong&gt;not yet fully implemented&lt;/strong&gt;. Fully implemented features are omitted. For complete design specs, see the linked source documents.&lt;/p&gt;
&lt;/blockquote&gt;&lt;hr&gt;
&lt;h2 id="deferred-explicitly-planned-for-future"&gt;Deferred (Explicitly Planned for Future)&lt;a class="anchor" href="#deferred-explicitly-planned-for-future"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="conditional-retry-retryif"&gt;Conditional Retry (&lt;code&gt;retryIf&lt;/code&gt;)&lt;a class="anchor" href="#conditional-retry-retryif"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/actions/"&gt;actions.md&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;Retry policies with a &lt;code&gt;retryIf&lt;/code&gt; condition to retry only on specific error types. Requires an &lt;code&gt;__error&lt;/code&gt; namespace with &lt;code&gt;message&lt;/code&gt;, &lt;code&gt;statusCode&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt;, &lt;code&gt;retryable&lt;/code&gt;, and &lt;code&gt;attempt&lt;/code&gt; fields.&lt;/p&gt;
&lt;h3 id="matrix-strategy"&gt;Matrix Strategy&lt;a class="anchor" href="#matrix-strategy"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/actions/"&gt;actions.md&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>Cache Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/cache-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/cache-tutorial/</guid><description>&lt;h1 id="managing-the-cache"&gt;Managing the Cache&lt;a class="anchor" href="#managing-the-cache"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial covers how to use scafctl&amp;rsquo;s cache management commands to view and clear cached data.&lt;/p&gt;
&lt;h2 id="what-is-cached"&gt;What is Cached?&lt;a class="anchor" href="#what-is-cached"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;scafctl caches certain data to improve performance:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Cache Type&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Use Case&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;HTTP Cache&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Responses from HTTP provider requests&lt;/td&gt;
 &lt;td&gt;Avoid repeated network calls&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Build Cache&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Incremental build fingerprints&lt;/td&gt;
 &lt;td&gt;Skip unchanged solution rebuilds&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Remote Artifact Cache&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Auto-cached artifacts from remote catalogs&lt;/td&gt;
 &lt;td&gt;Offline access to previously fetched solutions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Caching reduces network latency, speeds up builds, and allows offline access to previously fetched resources.&lt;/p&gt;</description></item><item><title>MCP Server for scafctl Solutions</title><link>https://oakwood-commons.github.io/scafctl/docs/design/mcp-server/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/mcp-server/</guid><description>&lt;h1 id="mcp-server-for-scafctl-solutions"&gt;MCP Server for scafctl Solutions&lt;a class="anchor" href="#mcp-server-for-scafctl-solutions"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This document evaluates building a &lt;a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer"&gt;Model Context Protocol (MCP)&lt;/a&gt;
 server for scafctl solutions. An MCP server exposes &lt;strong&gt;tools&lt;/strong&gt;, &lt;strong&gt;resources&lt;/strong&gt;, and &lt;strong&gt;prompts&lt;/strong&gt; over JSON-RPC 2.0 (typically via stdio or SSE) so that AI agents (Claude, Copilot, etc.) can discover and invoke them programmatically.&lt;/p&gt;
&lt;h2 id="how-an-mcp-server-works-internally"&gt;How an MCP Server Works Internally&lt;a class="anchor" href="#how-an-mcp-server-works-internally"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="the-big-picture"&gt;The Big Picture&lt;a class="anchor" href="#the-big-picture"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An MCP server is a &lt;strong&gt;long-running process&lt;/strong&gt; that sits between an AI agent (e.g., Claude, Copilot) and your application. It speaks a specific protocol (JSON-RPC 2.0) so the AI knows what capabilities are available and how to call them.&lt;/p&gt;</description></item><item><title>MCP Server Implementation Guide</title><link>https://oakwood-commons.github.io/scafctl/docs/design/mcp-server-implementation-guide/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/mcp-server-implementation-guide/</guid><description>&lt;h1 id="mcp-server-implementation-guide"&gt;MCP Server Implementation Guide&lt;a class="anchor" href="#mcp-server-implementation-guide"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This document is the detailed, step-by-step implementation guide for building the MCP server into scafctl. It is the companion to the &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/mcp-server/"&gt;MCP Server design document&lt;/a&gt;
 which covers the &lt;em&gt;why&lt;/em&gt; — this document covers the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before starting implementation, the following must be true:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All preparatory refactoring is &lt;strong&gt;complete&lt;/strong&gt; (see &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/mcp-server/#completed-preparatory-refactoring"&gt;mcp-server.md § Completed Preparatory Refactoring&lt;/a&gt;
)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pkg/mcp/context.go&lt;/code&gt; exists with &lt;code&gt;NewContext()&lt;/code&gt; and functional options&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pkg/cmd/scafctl/run/execute.go&lt;/code&gt; exports &lt;code&gt;ValidateSolution()&lt;/code&gt;, &lt;code&gt;ExecuteResolvers()&lt;/code&gt;, &lt;code&gt;ResolverExecutionConfigFromContext()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pkg/solution/prepare/prepare.go&lt;/code&gt; exports &lt;code&gt;Solution()&lt;/code&gt; with functional options&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pkg/cmd/scafctl/explain/results.go&lt;/code&gt; exports &lt;code&gt;BuildSolutionExplanation()&lt;/code&gt;, &lt;code&gt;LoadSolution()&lt;/code&gt;, &lt;code&gt;LookupProvider()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pkg/cmd/scafctl/get/celfunction/celfunction.go&lt;/code&gt; provides the &lt;code&gt;cel-functions&lt;/code&gt; command&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="decisions-summary"&gt;Decisions Summary&lt;a class="anchor" href="#decisions-summary"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These decisions were made during planning and are &lt;strong&gt;final&lt;/strong&gt; for this implementation:&lt;/p&gt;</description></item><item><title>MCP Server Enhancements &amp; CLI Parity</title><link>https://oakwood-commons.github.io/scafctl/docs/design/mcp-server-enhancements/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/mcp-server-enhancements/</guid><description>&lt;h1 id="mcp-server-enhancements--cli-parity"&gt;MCP Server Enhancements &amp;amp; CLI Parity&lt;a class="anchor" href="#mcp-server-enhancements--cli-parity"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This document is the implementation plan for the next phase of MCP server improvements and the introduction of CLI parity for MCP-only tools. It builds on the existing &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/mcp-server/"&gt;MCP Server design&lt;/a&gt;
 and &lt;a href="https://oakwood-commons.github.io/scafctl/docs/design/mcp-server-implementation-guide/"&gt;Implementation Guide&lt;/a&gt;
.&lt;/p&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;a class="anchor" href="#table-of-contents"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#motivation"&gt;Motivation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#part-1-cli-parity--exposing-mcp-tools-as-cli-commands"&gt;Part 1: CLI Parity — Exposing MCP Tools as CLI Commands&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#architecture-shared-library-pattern"&gt;Architecture: Shared Library Pattern&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-1a-scafctl-eval-command-group"&gt;Phase 1A: &lt;code&gt;scafctl eval&lt;/code&gt; Command Group&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-1b-scafctl-new-command"&gt;Phase 1B: &lt;code&gt;scafctl new&lt;/code&gt; Command&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-1c-scafctl-lint-subcommands"&gt;Phase 1C: &lt;code&gt;scafctl lint&lt;/code&gt; Subcommands&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-1e-scafctl-examples-command-group"&gt;Phase 1E: &lt;code&gt;scafctl examples&lt;/code&gt; Command Group&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-1f-enhanced---dry-run-output"&gt;Phase 1F: Enhanced &lt;code&gt;--dry-run&lt;/code&gt; Output&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#part-2-new-mcp-tools"&gt;Part 2: New MCP Tools&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#phase-2a-extract_resolver_refs"&gt;Phase 2A: &lt;code&gt;extract_resolver_refs&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2b-generate_test_scaffold"&gt;Phase 2B: &lt;code&gt;generate_test_scaffold&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2c-list_tests"&gt;Phase 2C: &lt;code&gt;list_tests&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2d-show_snapshot"&gt;Phase 2D: &lt;code&gt;show_snapshot&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2e-diff_snapshots"&gt;Phase 2E: &lt;code&gt;diff_snapshots&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2f-catalog_inspect"&gt;Phase 2F: &lt;code&gt;catalog_inspect&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2g-list_auth_handlers"&gt;Phase 2G: &lt;code&gt;list_auth_handlers&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2h-get_config_paths"&gt;Phase 2H: &lt;code&gt;get_config_paths&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-2i-validate_expressions-batch"&gt;Phase 2I: &lt;code&gt;validate_expressions&lt;/code&gt; (Batch)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#part-3-new-mcp-prompts"&gt;Part 3: New MCP Prompts&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#phase-3a-analyze_execution-prompt"&gt;Phase 3A: &lt;code&gt;analyze_execution&lt;/code&gt; Prompt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-3b-migrate_solution-prompt"&gt;Phase 3B: &lt;code&gt;migrate_solution&lt;/code&gt; Prompt&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-3c-optimize_solution-prompt"&gt;Phase 3C: &lt;code&gt;optimize_solution&lt;/code&gt; Prompt&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#part-4-new-mcp-resources"&gt;Part 4: New MCP Resources&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#phase-4a-solutionnametests-resource"&gt;Phase 4A: &lt;code&gt;solution://{name}/tests&lt;/code&gt; Resource&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#part-5-architecture--quality-improvements"&gt;Part 5: Architecture &amp;amp; Quality Improvements&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="#phase-5a-extract-shared-libraries-from-inline-mcp-code"&gt;Phase 5A: Extract Shared Libraries from Inline MCP Code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-5b-structured-error-context"&gt;Phase 5B: Structured Error Context&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-5c-tool-latency-hints"&gt;Phase 5C: Tool Latency Hints&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#phase-5d-get_version-tool"&gt;Phase 5D: &lt;code&gt;get_version&lt;/code&gt; Tool&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#implementation-order"&gt;Implementation Order&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#testing-strategy"&gt;Testing Strategy&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="motivation"&gt;Motivation&lt;a class="anchor" href="#motivation"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The MCP server currently exposes 26 tools, 9 prompts, and 5 resources. After analyzing the full codebase, two categories of improvements have been identified:&lt;/p&gt;</description></item><item><title>Provider Reference</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-reference/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-reference/</guid><description>&lt;h1 id="provider-reference"&gt;Provider Reference&lt;a class="anchor" href="#provider-reference"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This document provides a reference for all built-in providers in scafctl.&lt;/p&gt;
&lt;blockquote class='book-hint tip'&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; All YAML examples in this reference show only the relevant resolver or action snippet. To use them, place each snippet inside a complete solution file with &lt;code&gt;apiVersion&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;, &lt;code&gt;metadata&lt;/code&gt;, and &lt;code&gt;spec&lt;/code&gt; sections. See the &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/getting-started/"&gt;Getting Started&lt;/a&gt;
 tutorial for the full solution structure.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Providers are execution primitives used by resolvers and actions. Each provider has &lt;strong&gt;capabilities&lt;/strong&gt; that determine where it can be used:&lt;/p&gt;</description></item><item><title>Extension Concepts</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/extension-concepts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/extension-concepts/</guid><description>&lt;h1 id="extension-concepts"&gt;Extension Concepts&lt;a class="anchor" href="#extension-concepts"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;scafctl is built on two types of &lt;strong&gt;extensions&lt;/strong&gt;: &lt;strong&gt;providers&lt;/strong&gt; and &lt;strong&gt;auth handlers&lt;/strong&gt;. Each can be delivered as a &lt;strong&gt;builtin&lt;/strong&gt; (compiled into the scafctl binary) or as a &lt;strong&gt;plugin&lt;/strong&gt; (a standalone binary communicating over gRPC).&lt;/p&gt;
&lt;p&gt;This page defines the core terminology and links to the detailed development guides.&lt;/p&gt;
&lt;h2 id="terminology"&gt;Terminology&lt;a class="anchor" href="#terminology"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Definition&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Provider&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;A stateless execution unit that performs a single operation: fetching data (&lt;code&gt;from&lt;/code&gt;), transforming values (&lt;code&gt;transform&lt;/code&gt;), validating inputs (&lt;code&gt;validation&lt;/code&gt;), executing side effects (&lt;code&gt;action&lt;/code&gt;), or authenticating requests (&lt;code&gt;authentication&lt;/code&gt;). Providers are the building blocks used inside solution resolvers.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Auth Handler&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;A stateful authentication manager that handles identity verification, credential storage, token acquisition, and request injection. Auth handlers manage OAuth flows, cache tokens across invocations, and are used by providers (like &lt;code&gt;http&lt;/code&gt;) to authenticate outgoing requests.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Builtin&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;An extension compiled directly into the scafctl binary. Builtin extensions are registered at startup and require no external binaries. Contributing a builtin extension means adding code to the scafctl repository.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Plugin&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;An extension delivered as a standalone executable that communicates with scafctl over gRPC using &lt;a href="https://github.com/hashicorp/go-plugin" target="_blank" rel="noopener noreferrer"&gt;hashicorp/go-plugin&lt;/a&gt;
. Plugins run as separate processes, can be written in any gRPC-capable language, and are distributed independently via OCI catalogs, Go modules, or binary releases.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Extension&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Umbrella term for any provider or auth handler, whether builtin or plugin.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Capability&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;A declared feature of a provider (e.g., &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;, &lt;code&gt;action&lt;/code&gt;) or auth handler (e.g., &lt;code&gt;scopes_on_login&lt;/code&gt;, &lt;code&gt;tenant_id&lt;/code&gt;). Capabilities let scafctl adapt behavior dynamically without hardcoded knowledge of each extension.&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="extension-matrix"&gt;Extension Matrix&lt;a class="anchor" href="#extension-matrix"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;Builtin&lt;/strong&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;Plugin&lt;/strong&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Provider&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Compiled into scafctl; 16 built-in providers (http, cel, exec&amp;hellip;)&lt;/td&gt;
 &lt;td&gt;Standalone gRPC binary; auto-fetched from OCI catalogs&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Auth Handler&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Compiled into scafctl; 3 built-in handlers (entra, github, gcp)&lt;/td&gt;
 &lt;td&gt;Standalone gRPC binary; auto-fetched from OCI catalogs&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="when-to-choose-builtin-vs-plugin"&gt;When to Choose Builtin vs Plugin&lt;a class="anchor" href="#when-to-choose-builtin-vs-plugin"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Factor&lt;/th&gt;
 &lt;th&gt;Builtin&lt;/th&gt;
 &lt;th&gt;Plugin&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Distribution&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Ships with scafctl&lt;/td&gt;
 &lt;td&gt;Distributed independently&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Go only&lt;/td&gt;
 &lt;td&gt;Any language with gRPC support&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Dependency management&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Part of scafctl&amp;rsquo;s &lt;code&gt;go.mod&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Isolated dependencies&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Process isolation&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Runs in-process&lt;/td&gt;
 &lt;td&gt;Separate process (crash isolation)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Update cycle&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Tied to scafctl releases&lt;/td&gt;
 &lt;td&gt;Independent release cadence&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Use case&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Core functionality, general-purpose&lt;/td&gt;
 &lt;td&gt;Third-party integrations, proprietary logic&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Contributing&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;PR to scafctl repo&lt;/td&gt;
 &lt;td&gt;Publish to any OCI registry&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences-providers-vs-auth-handlers"&gt;Key Differences: Providers vs Auth Handlers&lt;a class="anchor" href="#key-differences-providers-vs-auth-handlers"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Aspect&lt;/th&gt;
 &lt;th&gt;Provider&lt;/th&gt;
 &lt;th&gt;Auth Handler&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Interface&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;2 methods: &lt;code&gt;Descriptor()&lt;/code&gt;, &lt;code&gt;Execute()&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;8+ methods: &lt;code&gt;Login()&lt;/code&gt;, &lt;code&gt;Logout()&lt;/code&gt;, &lt;code&gt;Status()&lt;/code&gt;, &lt;code&gt;GetToken()&lt;/code&gt;, &lt;code&gt;InjectAuth()&lt;/code&gt;, &amp;hellip;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Stateless — each execution is independent&lt;/td&gt;
 &lt;td&gt;Stateful — manages cached tokens, refresh tokens, sessions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Used by&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Solution resolvers (via &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;, etc.)&lt;/td&gt;
 &lt;td&gt;Providers (e.g., &lt;code&gt;http&lt;/code&gt; provider calls &lt;code&gt;InjectAuth()&lt;/code&gt; on requests)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Registry&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;provider.Registry&lt;/code&gt; (versioned, overwrite-protected)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;auth.Registry&lt;/code&gt; (name-keyed)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Capabilities&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;from&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;, &lt;code&gt;validation&lt;/code&gt;, &lt;code&gt;action&lt;/code&gt;, &lt;code&gt;authentication&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;scopes_on_login&lt;/code&gt;, &lt;code&gt;scopes_on_token_request&lt;/code&gt;, &lt;code&gt;tenant_id&lt;/code&gt;, &lt;code&gt;hostname&lt;/code&gt;, &lt;code&gt;federated_token&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Plugin artifact kind&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;auth-handler&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="plugin-communication"&gt;Plugin Communication&lt;a class="anchor" href="#plugin-communication"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Both provider plugins and auth handler plugins use &lt;a href="https://github.com/hashicorp/go-plugin" target="_blank" rel="noopener noreferrer"&gt;hashicorp/go-plugin&lt;/a&gt;
 with gRPC:&lt;/p&gt;</description></item><item><title>Provider Development Guide</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-development/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-development/</guid><description>&lt;h1 id="provider-development-guide"&gt;Provider Development Guide&lt;a class="anchor" href="#provider-development-guide"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide explains how to create custom providers for scafctl. Providers are the building blocks that perform operations like fetching data, transforming values, validating inputs, and executing actions.&lt;/p&gt;
&lt;p&gt;Providers can be delivered in two ways:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;Builtin&lt;/strong&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;Plugin&lt;/strong&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Where it lives&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Compiled into the scafctl binary&lt;/td&gt;
 &lt;td&gt;Separate executable (any language with gRPC)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Registration&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;registry.Register(...)&lt;/code&gt; in &lt;code&gt;builtin.go&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Discovered at runtime from plugin cache or catalog&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Crash isolation&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Shares process with scafctl&lt;/td&gt;
 &lt;td&gt;Isolated process — plugin crash doesn&amp;rsquo;t take down CLI&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Distribution&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Ships with scafctl releases&lt;/td&gt;
 &lt;td&gt;OCI catalog artifact (&lt;code&gt;kind: provider&lt;/code&gt;) or standalone binary&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Interface&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;provider.Provider&lt;/code&gt; (2 methods)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;plugin.ProviderPlugin&lt;/code&gt; (3 methods)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote class='book-hint warning'&gt;
&lt;p&gt;&lt;strong&gt;Prerequisite&lt;/strong&gt;: Read the &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/extension-concepts/"&gt;Extension Concepts&lt;/a&gt;
 page for terminology (provider vs plugin vs auth handler).&lt;/p&gt;</description></item><item><title>Auth Handler Development Guide</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/auth-handler-development/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/auth-handler-development/</guid><description>&lt;h1 id="auth-handler-development-guide"&gt;Auth Handler Development Guide&lt;a class="anchor" href="#auth-handler-development-guide"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This guide explains how to create custom auth handlers for scafctl. Auth handlers manage identity verification, credential storage, and token acquisition for identity providers (e.g., Entra ID, GitHub, GCP, Okta, AWS SSO).&lt;/p&gt;
&lt;p&gt;Auth handlers can be delivered in two ways:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;Builtin&lt;/strong&gt;&lt;/th&gt;
 &lt;th&gt;&lt;strong&gt;Plugin&lt;/strong&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Where it lives&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Compiled into the scafctl binary&lt;/td&gt;
 &lt;td&gt;Separate executable (any language with gRPC)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Registration&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;authRegistry.Register(...)&lt;/code&gt; in &lt;code&gt;root.go&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Discovered at runtime from plugin cache or catalog&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Credential storage&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Uses &lt;code&gt;pkg/secrets&lt;/code&gt; (OS keychain)&lt;/td&gt;
 &lt;td&gt;Plugin manages its own credential storage&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Crash isolation&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Shares process with scafctl&lt;/td&gt;
 &lt;td&gt;Isolated process — plugin crash doesn&amp;rsquo;t take down CLI&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Distribution&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Ships with scafctl releases&lt;/td&gt;
 &lt;td&gt;OCI catalog artifact (&lt;code&gt;kind: auth-handler&lt;/code&gt;) or standalone binary&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Interface&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;auth.Handler&lt;/code&gt; (8 methods)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;plugin.AuthHandlerPlugin&lt;/code&gt; (7 methods)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote class='book-hint warning'&gt;
&lt;p&gt;&lt;strong&gt;Prerequisite&lt;/strong&gt;: Read the &lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/extension-concepts/"&gt;Extension Concepts&lt;/a&gt;
 page for terminology (provider vs auth handler vs plugin).&lt;/p&gt;</description></item><item><title>Plugin Development Guide</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/plugin-development/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/plugin-development/</guid><description>&lt;h1 id="plugin-development-guide"&gt;Plugin Development Guide&lt;a class="anchor" href="#plugin-development-guide"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote class='book-hint note'&gt;
&lt;p&gt;&lt;strong&gt;This page is an overview.&lt;/strong&gt; Detailed plugin development instructions are now part of each extension type&amp;rsquo;s development guide.&lt;/p&gt;&lt;/blockquote&gt;&lt;h2 id="what-is-a-plugin"&gt;What is a Plugin?&lt;a class="anchor" href="#what-is-a-plugin"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A plugin is a standalone executable that extends scafctl by communicating over gRPC using &lt;a href="https://github.com/hashicorp/go-plugin" target="_blank" rel="noopener noreferrer"&gt;hashicorp/go-plugin&lt;/a&gt;
. Plugins run in separate processes, providing crash isolation and independent distribution.&lt;/p&gt;
&lt;p&gt;scafctl supports two types of plugins:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Plugin Type&lt;/th&gt;
 &lt;th&gt;Artifact Kind&lt;/th&gt;
 &lt;th&gt;Interface&lt;/th&gt;
 &lt;th&gt;Guide&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Provider Plugin&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;plugin.ProviderPlugin&lt;/code&gt; (3 methods)&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/provider-development/#delivering-as-a-plugin"&gt;Provider Development Guide — Delivering as a Plugin&lt;/a&gt;
&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Auth Handler Plugin&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;auth-handler&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;plugin.AuthHandlerPlugin&lt;/code&gt; (7 methods)&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://oakwood-commons.github.io/scafctl/docs/tutorials/auth-handler-development/#delivering-as-a-plugin"&gt;Auth Handler Development Guide — Delivering as a Plugin&lt;/a&gt;
&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;a class="anchor" href="#architecture"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;scafctl&amp;lt;br/&amp;gt;- Discovers plugin&amp;lt;br/&amp;gt;- Calls extension&amp;lt;br/&amp;gt;- Manages lifecycle&amp;#34;] &amp;lt;-- &amp;#34;gRPC&amp;#34; --&amp;gt; B[&amp;#34;Your Plugin&amp;lt;br/&amp;gt;- Implements gRPC&amp;lt;br/&amp;gt;- Exposes handlers&amp;lt;br/&amp;gt;- Handles execution&amp;#34;]&lt;/pre&gt;&lt;p&gt;Each plugin binary exposes &lt;strong&gt;one&lt;/strong&gt; extension type (provider OR auth handler). The handshake cookie determines which type the host expects.&lt;/p&gt;</description></item><item><title>Plugin Auto-Fetching</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/plugin-auto-fetch-tutorial/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/plugin-auto-fetch-tutorial/</guid><description>&lt;h1 id="plugin-auto-fetching-from-catalogs"&gt;Plugin Auto-Fetching from Catalogs&lt;a class="anchor" href="#plugin-auto-fetching-from-catalogs"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial explains how scafctl automatically fetches plugin binaries from remote catalogs at runtime. You can declare plugin dependencies in your solution, and scafctl will resolve, download, cache, and load them without a prior build step.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The plugin auto-fetch flow:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Solution declares Catalog chain Plugin cache Provider
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;plugin dependencies → resolves version → checks cache → registration
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (local → remote) (cache hit/miss) (gRPC plugin)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Declare&lt;/strong&gt; plugin dependencies in your solution&amp;rsquo;s &lt;code&gt;bundle.plugins&lt;/code&gt; section&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resolve&lt;/strong&gt; — scafctl looks up the plugin version in the catalog chain (local first, then remote OCI registries)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache&lt;/strong&gt; — if the binary is already cached locally, it&amp;rsquo;s reused; otherwise it&amp;rsquo;s fetched and written to the cache&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Load&lt;/strong&gt; — the cached binary is launched as a gRPC plugin and its providers are registered&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="declaring-plugin-dependencies"&gt;Declaring Plugin Dependencies&lt;a class="anchor" href="#declaring-plugin-dependencies"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Add a &lt;code&gt;bundle.plugins&lt;/code&gt; section to your solution:&lt;/p&gt;</description></item><item><title>Multi-Platform Plugin Build Tutorial</title><link>https://oakwood-commons.github.io/scafctl/docs/tutorials/multi-platform-plugin-build/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/tutorials/multi-platform-plugin-build/</guid><description>&lt;h1 id="multi-platform-plugin-build-tutorial"&gt;Multi-Platform Plugin Build Tutorial&lt;a class="anchor" href="#multi-platform-plugin-build-tutorial"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This tutorial walks through building and distributing multi-platform plugin
artifacts using OCI image indexes.&lt;/p&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Plugin artifacts (providers, auth handlers) are platform-specific binaries.
To distribute a single plugin that works on multiple OS/architecture
combinations, scafctl stores them as an &lt;strong&gt;OCI image index&lt;/strong&gt; (also called a
&amp;ldquo;fat manifest&amp;rdquo;). At runtime, scafctl automatically selects the correct
binary for the current platform.&lt;/p&gt;
&lt;h3 id="supported-platforms"&gt;Supported Platforms&lt;a class="anchor" href="#supported-platforms"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Platform&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;linux/amd64&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Linux x86-64&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;linux/arm64&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Linux ARM64 (e.g. AWS Graviton)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;darwin/amd64&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;macOS Intel&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;darwin/arm64&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;macOS Apple Silicon&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;windows/amd64&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Windows x86-64&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;a class="anchor" href="#prerequisites"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;scafctl CLI installed&lt;/li&gt;
&lt;li&gt;Go toolchain (for cross-compilation)&lt;/li&gt;
&lt;li&gt;Plugin source code that builds for multiple platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-1-cross-compile-the-plugin"&gt;Step 1: Cross-Compile the Plugin&lt;a class="anchor" href="#step-1-cross-compile-the-plugin"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use Go&amp;rsquo;s cross-compilation to build binaries for each target platform:&lt;/p&gt;</description></item><item><title/><link>https://oakwood-commons.github.io/scafctl/docs/design/api-surface/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/api-surface/</guid><description>&lt;h1 id="api-surface-design"&gt;API Surface Design&lt;a class="anchor" href="#api-surface-design"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Detailed API surface for the scafctl REST API server. All endpoints use JSON request/response bodies and follow REST conventions.&lt;/p&gt;
&lt;h2 id="base-url"&gt;Base URL&lt;a class="anchor" href="#base-url"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;http://localhost:8080&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Version-prefixed endpoints use &lt;code&gt;/{apiVersion}/&lt;/code&gt; (default: &lt;code&gt;/v1/&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="authentication"&gt;Authentication&lt;a class="anchor" href="#authentication"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method&lt;/strong&gt;: Entra OIDC (Azure AD) JWT Bearer tokens&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Header&lt;/strong&gt;: &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Public endpoints&lt;/strong&gt;: Health probes and metrics bypass authentication&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Admin endpoints&lt;/strong&gt;: Require authentication + &lt;code&gt;admin&lt;/code&gt; role claim (or localhost-only when auth is disabled)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="response-format"&gt;Response Format&lt;a class="anchor" href="#response-format"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="success-single-resource"&gt;Success (single resource)&lt;a class="anchor" href="#success-single-resource"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;fieldA&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;fieldB&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="success-collection-with-pagination"&gt;Success (collection with pagination)&lt;a class="anchor" href="#success-collection-with-pagination"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;items&amp;#34;&lt;/span&gt;: [&lt;span style="color:#f85149"&gt;...&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;pagination&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;page&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;per_page&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;100&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;total_items&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;250&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;total_pages&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;has_more&amp;#34;&lt;/span&gt;: &lt;span style="color:#79c0ff"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="error-rfc-7807-problem-details"&gt;Error (RFC 7807 Problem Details)&lt;a class="anchor" href="#error-rfc-7807-problem-details"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;&amp;#34;Bad Request&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;400&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7ee787"&gt;&amp;#34;detail&amp;#34;&lt;/span&gt;: &lt;span style="color:#a5d6ff"&gt;&amp;#34;validation failed: name is required&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="naming-conventions"&gt;Naming Conventions&lt;a class="anchor" href="#naming-conventions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Layer&lt;/th&gt;
 &lt;th&gt;Convention&lt;/th&gt;
 &lt;th&gt;Example&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Config (YAML/JSON)&lt;/td&gt;
 &lt;td&gt;camelCase&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;apiVersion&lt;/code&gt;, &lt;code&gt;shutdownTimeout&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;API response fields&lt;/td&gt;
 &lt;td&gt;snake_case&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;per_page&lt;/code&gt;, &lt;code&gt;total_items&lt;/code&gt;, &lt;code&gt;has_more&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;URL paths&lt;/td&gt;
 &lt;td&gt;lowercase, kebab-case for multi-word&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/solutions&lt;/code&gt;, &lt;code&gt;/v1/admin/reload-config&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Query parameters&lt;/td&gt;
 &lt;td&gt;snake_case&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;per_page&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="endpoints"&gt;Endpoints&lt;a class="anchor" href="#endpoints"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="operational-root-router--no-auth"&gt;Operational (Root Router — No Auth)&lt;a class="anchor" href="#operational-root-router--no-auth"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;API root with HATEOAS links&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/health&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Full health check with component status&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/health/live&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Liveness probe&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/health/ready&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Readiness probe&lt;/td&gt;
 &lt;td&gt;200, 503&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/metrics&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Prometheus metrics&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="solutions"&gt;Solutions&lt;a class="anchor" href="#solutions"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Query Params&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/solutions/run&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Run a solution (resolve + execute actions)&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400, 422&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/solutions/render&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Resolve inputs without executing actions&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400, 422&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/solutions/lint&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Lint a solution&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/solutions/inspect&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Inspect solution structure&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/solutions/test&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Validate solution against provider registry&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/solutions/dryrun&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Dry-run a solution (what-if analysis)&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400, 422&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="providers"&gt;Providers&lt;a class="anchor" href="#providers"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Query Params&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/providers&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List providers&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;page&lt;/code&gt;, &lt;code&gt;per_page&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/providers/{name}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Get provider details&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 404&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/providers/{name}/schema&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Get provider schema&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 404&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="eval"&gt;Eval&lt;a class="anchor" href="#eval"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/eval/cel&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Evaluate CEL expression&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/eval/template&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Evaluate Go template&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="catalogs"&gt;Catalogs&lt;a class="anchor" href="#catalogs"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Query Params&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/catalogs&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List catalogs&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;page&lt;/code&gt;, &lt;code&gt;per_page&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/catalogs/{name}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Get catalog details&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 404&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/catalogs/{name}/solutions&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List catalog solutions&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;page&lt;/code&gt;, &lt;code&gt;per_page&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;200, 404&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/catalogs/sync&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Sync catalogs (planned)&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="schemas"&gt;Schemas&lt;a class="anchor" href="#schemas"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Query Params&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/schemas&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List schemas&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;page&lt;/code&gt;, &lt;code&gt;per_page&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/schemas/{name}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Get schema&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 404&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/schemas/validate&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Validate against schema&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 400, 422&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="config"&gt;Config&lt;a class="anchor" href="#config"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/config&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Get current config&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/settings&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Get runtime settings&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="snapshots"&gt;Snapshots&lt;a class="anchor" href="#snapshots"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Query Params&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/snapshots&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;List snapshots (planned)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;page&lt;/code&gt;, &lt;code&gt;per_page&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/snapshots/{id}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Get snapshot details (planned)&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;200, 404&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="explain--diff"&gt;Explain &amp;amp; Diff&lt;a class="anchor" href="#explain--diff"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/explain&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Explain a solution&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/diff&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Diff solutions&lt;/td&gt;
 &lt;td&gt;200, 400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="admin"&gt;Admin&lt;a class="anchor" href="#admin"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Authorization&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/admin/info&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Server info&lt;/td&gt;
 &lt;td&gt;admin role / localhost&lt;/td&gt;
 &lt;td&gt;200, 403&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/admin/reload-config&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Hot-reload config (planned)&lt;/td&gt;
 &lt;td&gt;admin role / localhost&lt;/td&gt;
 &lt;td&gt;200, 403&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;POST&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/admin/clear-cache&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Clear caches (planned)&lt;/td&gt;
 &lt;td&gt;admin role / localhost&lt;/td&gt;
 &lt;td&gt;200, 403&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="documentation-auto-generated-by-huma"&gt;Documentation (Auto-Generated by Huma)&lt;a class="anchor" href="#documentation-auto-generated-by-huma"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Method&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Status Codes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/docs&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Interactive API documentation&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GET&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;/v1/openapi.json&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;OpenAPI specification (JSON)&lt;/td&gt;
 &lt;td&gt;200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="common-query-parameters"&gt;Common Query Parameters&lt;a class="anchor" href="#common-query-parameters"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Parameter&lt;/th&gt;
 &lt;th&gt;Type&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Constraints&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;page&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;int&lt;/td&gt;
 &lt;td&gt;Page number (1-indexed)&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;1–10000&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;per_page&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;int&lt;/td&gt;
 &lt;td&gt;Items per page&lt;/td&gt;
 &lt;td&gt;100&lt;/td&gt;
 &lt;td&gt;1–1000&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;string&lt;/td&gt;
 &lt;td&gt;CEL filter expression&lt;/td&gt;
 &lt;td&gt;—&lt;/td&gt;
 &lt;td&gt;max 2000 chars&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="global-status-codes"&gt;Global Status Codes&lt;a class="anchor" href="#global-status-codes"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These status codes can be returned by any endpoint, in addition to endpoint-specific codes:&lt;/p&gt;</description></item><item><title/><link>https://oakwood-commons.github.io/scafctl/docs/design/web-api-implementation-plan/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/web-api-implementation-plan/</guid><description>&lt;h1 id="web-api-implementation-plan"&gt;Web API Implementation Plan&lt;a class="anchor" href="#web-api-implementation-plan"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="overview"&gt;Overview&lt;a class="anchor" href="#overview"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Add a &lt;a href="https://github.com/danielgtaylor/huma" target="_blank" rel="noopener noreferrer"&gt;Huma&lt;/a&gt;
+&lt;a href="https://github.com/go-chi/chi" target="_blank" rel="noopener noreferrer"&gt;chi&lt;/a&gt;
-based REST API to scafctl, started via a new &lt;code&gt;scafctl serve&lt;/code&gt; command. The API mirrors all major CLI features (run, render, lint, eval, catalog, solutions, providers, config, etc.) with Entra OIDC authentication, Prometheus metrics, OpenTelemetry tracing, audit logging, CEL-based filtering, and admin endpoints.&lt;/p&gt;
&lt;p&gt;Architecture follows the &lt;a href="https://github.com/ford-cloud/jqapi" target="_blank" rel="noopener noreferrer"&gt;jqapi&lt;/a&gt;
 reference implementation: chi router → layered middleware → Huma endpoint registration → handler context with dependency injection. All operations are synchronous request-response initially, with an async task model planned as future work.&lt;/p&gt;</description></item><item><title>Entra ID Authentication Implementation Decision</title><link>https://oakwood-commons.github.io/scafctl/docs/design/entra-auth-implementation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://oakwood-commons.github.io/scafctl/docs/design/entra-auth-implementation/</guid><description>&lt;h1 id="entra-id-authentication-manual-implementation-vs-msal"&gt;Entra ID Authentication: Manual Implementation vs MSAL&lt;a class="anchor" href="#entra-id-authentication-manual-implementation-vs-msal"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="status"&gt;Status&lt;a class="anchor" href="#status"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Decided&lt;/strong&gt; — Manual implementation retained.&lt;/p&gt;
&lt;h2 id="context"&gt;Context&lt;a class="anchor" href="#context"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;pkg/auth/entra&lt;/code&gt; package implements OAuth 2.0 authentication against Azure Entra ID (formerly Azure AD). A question arose whether to use the official &lt;a href="https://github.com/AzureAD/microsoft-authentication-library-for-go" target="_blank" rel="noopener noreferrer"&gt;Microsoft Authentication Library for Go (MSAL)&lt;/a&gt;
 instead of the current hand-rolled implementation.&lt;/p&gt;
&lt;h2 id="current-implementation"&gt;Current Implementation&lt;a class="anchor" href="#current-implementation"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The package manually implements all OAuth 2.0 flows using raw &lt;code&gt;net/http&lt;/code&gt; POST calls to Azure Entra ID token endpoints. There are zero Azure SDK or MSAL dependencies in the project.&lt;/p&gt;</description></item></channel></rss>