Documentation
¶
Overview ¶
Agent command for sprout
Agent execution utilities: command execution, formatting, and helper functions
Simple enhanced agent command with web UI support Flag variables for web UI configuration (used by agent_modes.go)
Agent modes: handles interactive and direct execution modes
Agent query processing: handles query execution and detection
daemon_logging.go — Daemon log rotation via lumberjack.
When sprout runs as a daemon (SPROUT_SERVICE=1), this module redirects os.Stdout and os.Stderr to lumberjack.Logger instances so that log files are automatically rotated. This replaces the approach of letting launchd / systemd / nohup write to fixed files and provides uniform rotation on every platform.
Package cmd provides the `sprout explain` subcommand (SP-068 Phase 3) for human-readable risk assessment of commands and tool calls.
Export training data command for sprout ¶
Plan command for sprout - Seamless planning and execution using agent framework ¶
Shell command for sprout
Index ¶
- func AgentSocketPath() string
- func ConfirmPrompt(msg string) bool
- func EmbeddingSocketPath() string
- func Execute() error
- func ExecuteCommand(cmd string) (string, error)
- func FormatDuration(d time.Duration) string
- func GetTerminalWidth() int
- func IsCI() bool
- func ProcessQuery(ctx context.Context, chatAgent *agent.Agent, _ *events.EventBus, query string) error
- func RunAgent(chatAgent *agent.Agent, isInteractive bool, args []string) (err error)
- func SetupAgentEvents(chatAgent *agent.Agent, eventBus *events.EventBus, ...)
- func StdinIsTerminal() bool
- func TryZshCommandExecution(ctx context.Context, chatAgent *agent.Agent, query string) (bool, error)
- func WriteTestSession(stateDir, sessionID, workingDir string, cs agent.ConversationState) (string, error)
- type AgentResult
- type AgentResultMetrics
- type AgentWorkflowBudgetConfig
- type AgentWorkflowConfig
- type AgentWorkflowInitial
- type AgentWorkflowLoopConfig
- type AgentWorkflowOrchestrationConfig
- type AgentWorkflowProgressConfig
- type AgentWorkflowRuntime
- type AgentWorkflowStep
- type BaseCommand
- type CommandConfig
- type CommandFlags
- type InstanceInfo
- type PendingInput
- type PricingRow
- type PromptIntent
- type SharedAgentService
- func (s *SharedAgentService) CreateSession(_ context.Context, name string) (*daemon.SessionInfo, error)
- func (s *SharedAgentService) ExecuteTool(context.Context, string, map[string]any) (*daemon.ToolResult, error)
- func (s *SharedAgentService) ListSessions(context.Context) ([]daemon.SessionInfo, error)
- func (s *SharedAgentService) Query(_ context.Context, prompt, workDir string) (string, error)
- func (s *SharedAgentService) StreamQuery(_ context.Context, prompt, workDir string, emit func(daemon.StreamEvent) error) error
- func (s *SharedAgentService) SwitchSession(_ context.Context, sessionID string) (*daemon.SessionInfo, error)
- func (s *SharedAgentService) WaitForTeardown()
- type SteerCoordinator
- func (c *SteerCoordinator) DrainPendingInput() PendingInput
- func (c *SteerCoordinator) EndTurn()
- func (c *SteerCoordinator) SetCompleter(p console.CompletionProvider)
- func (c *SteerCoordinator) SetGroundTruth(gt *console.GroundTruthTermios)
- func (c *SteerCoordinator) SetRichCompleter(rc console.RichCompletionProvider)
- func (c *SteerCoordinator) StartTurn()
- type WorkflowExecutionState
- type WorkflowSubagentOverride
- type WorkflowSubagentOverrides
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AgentSocketPath ¶ added in v0.17.17
func AgentSocketPath() string
AgentSocketPath returns the daemon agent socket path, honoring the SPROUT_DAEMON_AGENT_SOCKET override.
func ConfirmPrompt ¶
ConfirmPrompt displays a confirmation prompt to the user and reads their response from stdin. It returns true only if the user types "y" or "yes" (case-insensitive). Any other input (including empty) returns false. If reading from stdin fails (e.g., not a TTY), it returns false. The prompt is written to stderr so it doesn't interfere with stdout capture. The msg should NOT include the y/N suffix — it is appended automatically with the default letter bolded when stderr is a terminal.
func EmbeddingSocketPath ¶ added in v0.17.17
func EmbeddingSocketPath() string
EmbeddingSocketPath returns the daemon embedding socket path, honoring the SPROUT_DAEMON_EMBEDDING_SOCKET override.
func Execute ¶
func Execute() error
Execute adds all child commands to the root command and sets flags appropriately. This is called by main.main(). It only needs to happen once to the rootCmd.
func ExecuteCommand ¶
ExecuteCommand runs a shell command and streams its output in real-time. Returns the combined output (for error messages) and any error that occurred.
func FormatDuration ¶
FormatDuration formats duration in human readable format
func GetTerminalWidth ¶
func GetTerminalWidth() int
GetTerminalWidth attempts to get the terminal width for separators Returns a conservative width to avoid wrapping
func ProcessQuery ¶
func ProcessQuery(ctx context.Context, chatAgent *agent.Agent, _ *events.EventBus, query string) error
ProcessQuery processes a single query. The eventBus parameter is retained for the workflow.QueryExecutor signature contract; events now publish via chatAgent.PublishEvent which auto-decorates with client_id/chat_id metadata.
func SetupAgentEvents ¶
func SetupAgentEvents(chatAgent *agent.Agent, eventBus *events.EventBus, indicator *console.ActivityIndicator)
SetupAgentEvents configures the agent for event-driven output routing. The OutputRouter handles dual-path delivery (EventBus + terminal) so no separate streaming callback is needed here. This function ensures the agent's output router is wired to the event bus for WebUI subscribers.
When indicator is non-nil, the streaming callback also stops it on the first chunk so any "Thinking…" spinner is cleared before tokens appear.
func StdinIsTerminal ¶
func StdinIsTerminal() bool
StdinIsTerminal returns true if os.Stdin is connected to a terminal. Used by command handlers to decide whether to show interactive prompts. If testIsTerminal is set (in tests), it delegates to that function.
func TryZshCommandExecution ¶
func TryZshCommandExecution(ctx context.Context, chatAgent *agent.Agent, query string) (bool, error)
tryZshCommandExecution attempts to detect and execute zsh commands directly Returns true if command was executed, false if normal flow should proceed
func WriteTestSession ¶ added in v0.16.18
func WriteTestSession(stateDir, sessionID, workingDir string, cs agent.ConversationState) (string, error)
WriteTestSession creates a valid session JSON file in the scoped sessions directory for a given session ID and working directory. Returns the absolute path of the written file.
Types ¶
type AgentResult ¶
type AgentResult struct {
Status string `json:"status"` // "success" or "error"
Error string `json:"error,omitempty"` // error message if status=="error"
Query string `json:"query"` // the original prompt
FilesModified []string `json:"files_modified,omitempty"` // files changed during execution
GitDiff string `json:"git_diff,omitempty"` // unified diff of all changes
PullRequestURL string `json:"pull_request_url,omitempty"` // URL of PR created during execution
Metrics AgentResultMetrics `json:"metrics"`
}
AgentResult is the structured output produced when --output-format=json is used. It captures everything a SaaS wrapper (e.g. Sprout Foundry) needs from a non-interactive sprout run.
type AgentResultMetrics ¶
type AgentResultMetrics struct {
ElapsedSeconds float64 `json:"elapsed_seconds"`
TokensIn int `json:"tokens_in"` // Total prompt/input tokens
TokensOut int `json:"tokens_out"` // Total completion/output tokens
LLMCalls int `json:"llm_calls"` // Number of LLM API calls made
Cost float64 `json:"cost"` // Total estimated USD cost
Provider string `json:"provider"` // LLM provider name (e.g., "openai", "anthropic")
Model string `json:"model"` // Model identifier (e.g., "gpt-4o")
// Security telemetry — track post-caution LLM behavior so external tools
// can measure SECURITY_CAUTION_REQUIRED signal effectiveness.
SecurityCautionsIssued int64 `json:"security_cautions_issued"` // Times a SECURITY_CAUTION_REQUIRED was produced
SecurityRetriesAfterCaution int64 `json:"security_retries_after_caution"` // Times the LLM retried the same blocked op after a caution
SecurityLoopsDetected int64 `json:"security_loops_detected"` // Times loop-detection fired (3+ identical blocks)
}
AgentResultMetrics holds execution metrics for structured output.
type AgentWorkflowBudgetConfig ¶ added in v0.16.4
type AgentWorkflowBudgetConfig = workflow.AgentWorkflowBudgetConfig
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type AgentWorkflowConfig ¶
type AgentWorkflowConfig = workflow.AgentWorkflowConfig
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type AgentWorkflowInitial ¶
type AgentWorkflowInitial = workflow.AgentWorkflowInitial
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type AgentWorkflowLoopConfig ¶ added in v0.16.19
type AgentWorkflowLoopConfig = workflow.AgentWorkflowLoopConfig
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type AgentWorkflowOrchestrationConfig ¶
type AgentWorkflowOrchestrationConfig = workflow.AgentWorkflowOrchestrationConfig
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type AgentWorkflowProgressConfig ¶ added in v0.16.4
type AgentWorkflowProgressConfig = workflow.AgentWorkflowProgressConfig
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type AgentWorkflowRuntime ¶
type AgentWorkflowRuntime = workflow.AgentWorkflowRuntime
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type AgentWorkflowStep ¶
type AgentWorkflowStep = workflow.AgentWorkflowStep
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type BaseCommand ¶
type BaseCommand struct {
// contains filtered or unexported fields
}
BaseCommand provides common functionality for all CLI commands
func NewBaseCommand ¶
func NewBaseCommand(use, short, long string) *BaseCommand
NewBaseCommand creates a new base command with common functionality
func (*BaseCommand) AddCustomFlag ¶
func (b *BaseCommand) AddCustomFlag(name, shorthand, defaultValue, description string) *string
AddCustomFlag adds a custom flag to the command
func (*BaseCommand) GetCommand ¶
func (b *BaseCommand) GetCommand() *cobra.Command
GetCommand returns the underlying cobra command
func (*BaseCommand) Initialize ¶
func (b *BaseCommand) Initialize() error
Initialize sets up common command infrastructure
func (*BaseCommand) SetRunFunc ¶
func (b *BaseCommand) SetRunFunc(fn func(*CommandConfig, []string) error)
SetRunFunc sets the command's run function with common initialization. CLI-G-1: errors surface via console.GlyphError.Fprintln so they hit the terminal stderr (with NO_COLOR / FORCE_COLOR honored) instead of being routed through log.Printf to ~/.sprout/workspace.log, which was the bug class behind "silent exit on broken config".
type CommandConfig ¶
type CommandConfig struct {
SkipPrompt bool
Model string
DryRun bool
Logger *utils.Logger
Config *configuration.Config
TraceSession *trace.TraceSession
TraceDatasetDir string
}
CommandConfig represents the common configuration shared across commands
type CommandFlags ¶
CommandFlags defines common flags used across commands
type InstanceInfo ¶
type InstanceInfo struct {
ID string `json:"id"`
Port int `json:"port"`
PID int `json:"pid"`
StartTime time.Time `json:"start_time"`
WorkingDir string `json:"working_dir"`
LastPing time.Time `json:"last_ping"`
SessionID string `json:"session_id,omitempty"`
}
InstanceInfo represents a running sprout instance
type PendingInput ¶ added in v0.16.17
type PendingInput struct {
// InitialContent is text to pre-fill in the next prompt (unsent
// steer text the user may want to edit before submitting).
InitialContent string
// QueuedMessages are raw deferred messages in FIFO order, ready to
// auto-submit as their own turns when the REPL loop processes them.
QueuedMessages []string
// QueuedCount is how many deferred messages were drained (for
// footer badge clearing and logging).
QueuedCount int
}
PendingInput captures all text that should carry over from one turn to the next: unsent steer text (typed but not submitted) and queued messages (submitted via Tab+Enter QUEUE mode). The REPL loop drains both in a single call to DrainPendingInput after EndTurn, eliminating the two-channel confusion where unsent text and queued messages followed different code paths.
type PricingRow ¶ added in v0.16.4
type PricingRow struct {
Provider string
Model string
InputUsdPerM float64
OutputUsdPerM float64
HasPricing bool
}
PricingRow is a single model's per-million-token rates.
type PromptIntent ¶ added in v0.16.2
type PromptIntent string
PromptIntent labels a piece of submitted text by which of the main REPL's pre-LLM interception classes it would fall into. The empty string means freeform text destined for the model.
Used by the steer / queue submit handlers (cmd/steer_coordinator.go) to reject submissions that would silently lose their command meaning if injected mid-turn or wrapped into the deferred-queue blockquote. Bang-prefixed shell commands are an exception: they execute mid-turn (steer) or enqueue for auto-run (queue), both of which dispatch them through the command registry's ! → exec translation.
const ( IntentNone PromptIntent = "" IntentSlash PromptIntent = "slash command" IntentBangShell PromptIntent = "shell command (! prefix)" IntentDetectedSh PromptIntent = "shell command" )
func ClassifyPromptIntent ¶ added in v0.16.2
func ClassifyPromptIntent(chatAgent *agent.Agent, text string) PromptIntent
ClassifyPromptIntent mirrors the dispatch decisions the main REPL makes BEFORE handing a query to the LLM. The classifier returns the first matching category in the same precedence order the REPL uses:
- Slash / bang prefix → registry.IsSlashCommand
- Zsh-detected command (config-gated) → zsh.IsCommand
Returns IntentNone for plain text. The chatAgent argument may be nil in tests; in that case the config-gated checks are skipped.
Keep this in lockstep with cmd/agent_modes.go's main-prompt dispatch (the IsSlashCommand check and the TryZshCommandExecution fast-path block). If a new pre-LLM interception lands at the prompt, add it here too — otherwise the steer/queue panels will diverge from the prompt's behavior.
type SharedAgentService ¶ added in v0.17.17
type SharedAgentService struct {
// contains filtered or unexported fields
}
SharedAgentService adapts the daemon to the SP-136 P4 agent socket protocol. The daemon is a single long-lived process that may serve one-shot queries from many different callers, in many different project directories, over its lifetime — Query/StreamQuery must not let one call's state (conversation history, workspace root) leak into another's.
So Query/StreamQuery build a fresh, throwaway *agent.Agent per call rather than reusing a shared one: agent construction resolves to the same process-wide local-model singleton either way (pkg/factory/factory.go → localmodel.GetLocalProvider()), so this doesn't reload the GPU-resident model — it only costs the (cheap) Agent object construction, in exchange for correct per-call isolation.
`a` is retained only for the (currently client-unused) session RPCs below, which predate the fix and don't go through the one-shot query path. Tool execution via the socket is not yet wired (ExecuteTool below) — callers fall back to in-process for full tool workflows.
func NewSharedAgentService ¶ added in v0.17.17
func NewSharedAgentService(a *agent.Agent) *SharedAgentService
NewSharedAgentService wraps an agent for socket serving.
func (*SharedAgentService) CreateSession ¶ added in v0.17.17
func (s *SharedAgentService) CreateSession(_ context.Context, name string) (*daemon.SessionInfo, error)
CreateSession implements daemon.AgentService.
func (*SharedAgentService) ExecuteTool ¶ added in v0.17.17
func (s *SharedAgentService) ExecuteTool(context.Context, string, map[string]any) (*daemon.ToolResult, error)
ExecuteTool implements daemon.AgentService.
func (*SharedAgentService) ListSessions ¶ added in v0.17.17
func (s *SharedAgentService) ListSessions(context.Context) ([]daemon.SessionInfo, error)
ListSessions implements daemon.AgentService.
func (*SharedAgentService) Query ¶ added in v0.17.17
Query implements daemon.AgentService: a fresh, isolated agent per call (see the type doc for why), scoped to the caller's workDir.
func (*SharedAgentService) StreamQuery ¶ added in v0.17.17
func (s *SharedAgentService) StreamQuery(_ context.Context, prompt, workDir string, emit func(daemon.StreamEvent) error) error
StreamQuery implements daemon.AgentService (one-shot result as a single delta; full token streaming is a future protocol refinement).
func (*SharedAgentService) SwitchSession ¶ added in v0.17.17
func (s *SharedAgentService) SwitchSession(_ context.Context, sessionID string) (*daemon.SessionInfo, error)
SwitchSession implements daemon.AgentService.
func (*SharedAgentService) WaitForTeardown ¶ added in v0.17.17
func (s *SharedAgentService) WaitForTeardown()
WaitForTeardown blocks until every ephemeral agent released so far has finished shutting down, bounded to 10s so a hung Agent.Shutdown can't wedge daemon exit forever. AgentServer.OnClose calls it so the daemon does not exit while an agent is still flushing its embedding store.
type SteerCoordinator ¶
type SteerCoordinator struct {
// contains filtered or unexported fields
}
SteerCoordinator owns the lifecycle of the pinned steer-input panel across an interactive session (SP-055). It wires the SteerInputReader's submit and interrupt callbacks to the agent's InjectInputContext / TriggerInterrupt once, and toggles the reader on/off around each ProcessQuery call via StartTurn / EndTurn.
Lifecycle:
c := NewSteerCoordinator(chatAgent, footer)
for {
query := inputReader.ReadLine()
c.StartTurn()
ProcessQuery(...)
c.EndTurn()
}
Non-TTY runs construct a coordinator whose reader is a no-op, so callers don't need to gate the calls.
Future polish hooks here: mode-indicator glyphs and steer history recall ("done queue" auto-run shipped as SP-055 Phase 3b). Keeping the coordinator behind a single small surface (StartTurn / EndTurn) means future features can land without touching the REPL loop.
func NewSteerCoordinator ¶
func NewSteerCoordinator(chatAgent *agent.Agent, footer *console.StatusFooter) *SteerCoordinator
NewSteerCoordinator constructs the coordinator with the SteerInputReader's callbacks already bound to the agent. The reader is created once and reused for every turn; SteerInputReader.Start/Stop reset its internal buffer between cycles.
chatAgent and footer may be nil for tests; in that case StartTurn and EndTurn are no-ops.
func (*SteerCoordinator) DrainPendingInput ¶ added in v0.16.17
func (c *SteerCoordinator) DrainPendingInput() PendingInput
DrainPendingInput consolidates the two carry-over paths (unsent steer buffer + deferred queue messages) into a single drain. The REPL loop calls this once after EndTurn instead of separately calling DrainUnsentBuffer and DrainDeferredMessages.
When both paths have content, the unsent text becomes the initial content (pre-filled for editing) and the queued messages are returned raw so the REPL can auto-submit each as its own turn.
func (*SteerCoordinator) EndTurn ¶
func (c *SteerCoordinator) EndTurn()
EndTurn deactivates the steer reader and tears down the pinned line. Safe to call when already stopped.
func (*SteerCoordinator) SetCompleter ¶ added in v0.16.18
func (c *SteerCoordinator) SetCompleter(p console.CompletionProvider)
SetCompleter installs a slash-command completion provider on the steer reader (SP-078 Phase 2). Bound to Ctrl-] — Tab is reserved for the STEER ↔ QUEUE mode toggle. The same provider can be passed to both inputReader.SetCompleter (Tab, REPL prompt) and steerCoord.SetCompleter (Ctrl-], mid-turn) so completion works in both surfaces.
func (*SteerCoordinator) SetGroundTruth ¶ added in v0.16.1
func (c *SteerCoordinator) SetGroundTruth(gt *console.GroundTruthTermios)
SetGroundTruth installs the REPL's pristine termios snapshot into the steer reader so Stop() restores to a known-good state instead of a potentially-corrupted per-enter snapshot.
func (*SteerCoordinator) SetRichCompleter ¶ added in v0.17.7
func (c *SteerCoordinator) SetRichCompleter(rc console.RichCompletionProvider)
SetRichCompleter installs a structured slash-command provider on the steer reader (SP-078 Phase 3). When set, the steer panel renders a live dropdown above the input line while the user types a "/"-prefixed command — same UX as the InputReader's dropdown. Tab accepts the highlighted candidate; Esc dismisses the dropdown; Up/Down navigate candidates while the dropdown is visible.
func (*SteerCoordinator) StartTurn ¶
func (c *SteerCoordinator) StartTurn()
StartTurn activates the steer reader for the duration of a ProcessQuery call. Safe to call when the reader is already active (idempotent, the reader's own Start enforces this).
Also registers the pause/resume hooks so interactive prompts (e.g. security elevation in pkg/utils.AskForConfirmation) can hand stdin back to cooked mode without fighting the steer reader for bytes. Without this hook the prompt's bufio.Reader hits EOF immediately and auto-rejects with "stdin unavailable - rejecting for safety".
type WorkflowExecutionState ¶ added in v0.17.3
type WorkflowExecutionState = workflow.WorkflowExecutionState
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type WorkflowSubagentOverride ¶ added in v0.17.3
type WorkflowSubagentOverride = workflow.WorkflowSubagentOverride
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
type WorkflowSubagentOverrides ¶
type WorkflowSubagentOverrides = workflow.WorkflowSubagentOverrides
Type aliases so existing cmd/ code can reference workflow types without changing every call site. The real definitions live in pkg/workflow.
Source Files
¶
- agent_command.go
- agent_exec_utils.go
- agent_execution.go
- agent_help.go
- agent_mode_direct.go
- agent_mode_interactive.go
- agent_mode_state.go
- agent_mode_utils.go
- agent_modes.go
- agent_modes_events.go
- agent_progress.go
- agent_query.go
- agent_result.go
- agent_socket.go
- agent_workflow.go
- audit.go
- automate.go
- automate_list.go
- automate_logs.go
- automate_pricing.go
- automate_process_group.go
- automate_run.go
- automate_run_overview_helpers.go
- automate_status.go
- automate_stop.go
- base.go
- cli_error.go
- cli_wakeup_poller.go
- commit.go
- common.go
- config.go
- confirm.go
- custom.go
- custom_helpers.go
- daemon_autostart.go
- daemon_idle.go
- daemon_logging.go
- daemon_oom.go
- diag.go
- embedding_socket.go
- embeddings.go
- explain.go
- export.go
- export_training.go
- first_run_hint.go
- history.go
- index_recommendation.go
- instance_registry.go
- keys.go
- keys_backend.go
- keys_set.go
- local_provider.go
- log.go
- log_redirect.go
- lsp.go
- malloc_env.go
- mcp.go
- mcp_add.go
- mcp_list.go
- mcp_remove.go
- mcp_test_cmd.go
- memlimit.go
- onboarding.go
- onboarding_local.go
- plan.go
- policy.go
- pr.go
- process_starttime.go
- process_starttime_linux.go
- prompt_intent.go
- recent_sessions.go
- review_staged.go
- root.go
- search.go
- serve.go
- service_cmd.go
- shell.go
- shell_bg.go
- skill.go
- skills.go
- slash_completer.go
- steer_coordinator.go
- training_wire.go
- upgrade.go
- version.go
- webui_handoff.go
- webui_supervisor.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Command enrich_registry annotates freshly-generated canonical model files with capability-probe results.
|
Command enrich_registry annotates freshly-generated canonical model files with capability-probe results. |
|
Command model_probe runs the capability probe against a single provider/model and prints the result as JSON.
|
Command model_probe runs the capability probe against a single provider/model and prints the result as JSON. |
|
Command model_registry_server runs a lightweight static file server for serving per-provider model JSON files.
|
Command model_registry_server runs a lightweight static file server for serving per-provider model JSON files. |
|
Command sync_provider_configs updates the embedded provider config models.available_models field to match the canonical registry.
|
Command sync_provider_configs updates the embedded provider config models.available_models field to match the canonical registry. |
|
Command validate_registry checks every providers/*.json against the runtime schema before the publish workflow uploads to GitHub Pages.
|
Command validate_registry checks every providers/*.json against the runtime schema before the publish workflow uploads to GitHub Pages. |