services

package
v0.1.155 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 24, 2026 License: MIT Imports: 22 Imported by: 6

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ErrorMessage added in v0.1.89

func ErrorMessage(err error, msg string, args ...any) string

func KustomizeOutput added in v0.1.75

func KustomizeOutput() *builderv0.DeploymentOutput

func NOOP added in v0.1.20

func NOOP() *runtimev0.DesiredState

func NetworkInstanceForRestRouteGroup added in v0.1.82

func NetworkInstanceForRestRouteGroup(ctx context.Context, mappings []*basev0.NetworkMapping, group *resources.RestRouteGroup, networkAccess *basev0.NetworkAccess) (*basev0.NetworkInstance, error)

NetworkInstanceForRestRouteGroup finds the proper network mapping for a given REST route group

Types

type Agent added in v0.0.51

type Agent interface {
	GetAgentInformation(ctx context.Context, req *agentv0.AgentInformationRequest) (*agentv0.AgentInformation, error)
}

Agent is the Go interface that plugin types implement on the server side.

type Base added in v0.0.26

type Base struct {
	// Satisfies agentv0.AgentServer for all plugins that embed *Base.
	agentv0.UnimplementedAgentServer

	// Agent
	Agent *resources.Agent
	Wool  *wool.Wool

	// Service logger
	Logger *wool.Wool

	// State
	Identity *resources.ServiceIdentity

	// Location of the service
	Location string

	// codefly configuration
	ConfigurationLocation string

	Service *resources.Service

	Environment *basev0.Environment

	// Information convenience
	Information *Information

	// Endpoints
	Endpoints           []*basev0.Endpoint
	DependencyEndpoints []*basev0.Endpoint

	NetworkMappings []*basev0.NetworkMapping

	// EnvironmentVariables
	EnvironmentVariables *resources.EnvironmentVariableManager

	// Configuration
	Configuration           *basev0.Configuration
	WorkspaceConfigurations []*basev0.Configuration

	// Wrappers
	Runtime *RuntimeWrapper
	Builder *BuilderWrapper

	// Runtime
	State InformationStatus

	// Code Watcher
	Watcher *code.Watcher
	Events  chan code.Change
	// contains filtered or unexported fields
}

func NewServiceBase added in v0.0.26

func NewServiceBase(ctx context.Context, agent *resources.Agent) *Base

func (*Base) BaseEndpoint added in v0.1.127

func (s *Base) BaseEndpoint(api string) *resources.Endpoint

func (*Base) DockerImage added in v0.0.31

func (s *Base) DockerImage(req *builderv0.DockerBuildContext) *resources.DockerImage

func (*Base) Errorf added in v0.0.28

func (s *Base) Errorf(format string, args ...any) error

func (*Base) HeadlessLoad added in v0.1.50

func (s *Base) HeadlessLoad(ctx context.Context, identity *basev0.ServiceIdentity) error

func (*Base) Infof added in v0.1.89

func (s *Base) Infof(msg string, args ...any)

func (*Base) ListCommands added in v0.1.155

ListCommands implements agentv0.AgentServer.

func (*Base) Load added in v0.0.72

func (s *Base) Load(ctx context.Context, identity *basev0.ServiceIdentity, settings any) error

func (*Base) Local added in v0.0.26

func (s *Base) Local(f string, args ...any) string

func (*Base) LocalDirCreate added in v0.1.39

func (s *Base) LocalDirCreate(ctx context.Context, f string, args ...any) (string, error)

func (*Base) RegisterBaseCommands added in v0.1.155

func (s *Base) RegisterBaseCommands()

RegisterBaseCommands registers commands available on every agent. Called automatically during Load.

func (*Base) RegisterCommand added in v0.1.155

func (s *Base) RegisterCommand(def *agentv0.CommandDefinition, handler CommandHandler)

RegisterCommand registers a command on the agent's base.

func (*Base) RunPluginCommand added in v0.1.155

RunPluginCommand implements agentv0.AgentServer.

func (*Base) SetDefaultDockerImage added in v0.1.124

func (s *Base) SetDefaultDockerImage(req *builderv0.DockerBuildContext)

func (*Base) SetDockerImage added in v0.1.124

func (s *Base) SetDockerImage(image *resources.DockerImage)

func (*Base) SetupWatcher added in v0.0.26

func (s *Base) SetupWatcher(ctx context.Context, conf *WatchConfiguration, handler func(event code.Change) error) error

func (*Base) Templates added in v0.0.26

func (s *Base) Templates(ctx context.Context, obj any, wrappers ...*TemplateWrapper) error

func (*Base) Unique added in v0.1.6

func (s *Base) Unique() string

func (*Base) UniqueWithWorkspace added in v0.1.89

func (s *Base) UniqueWithWorkspace() string

func (*Base) Version added in v0.0.26

func (s *Base) Version() *basev0.Version

type BuilderAgent added in v0.1.20

type BuilderAgent struct {
	builderv0.BuilderClient
	Agent       *resources.Agent
	ProcessInfo *manager.ProcessInfo
}

BuilderAgent is the client-side wrapper for the Builder gRPC service.

func NewBuilderAgentClient added in v0.1.155

func NewBuilderAgentClient(conn *grpc.ClientConn) *BuilderAgent

NewBuilderAgentClient creates a BuilderAgent from an existing gRPC connection.

type BuilderServer added in v0.1.20

type BuilderServer struct {
	builderv0.UnimplementedBuilderServer
}

BuilderServer is embedded by plugin builder types to satisfy the gRPC BuilderServer interface. Plugins override methods they implement.

type BuilderWrapper added in v0.1.20

type BuilderWrapper struct {
	*Base

	BuildResult  *builderv0.BuildResult
	DeployOutput *builderv0.DeploymentOutput

	GettingStarted string

	CreationMode *builderv0.CreationMode
	SyncMode     *builderv0.SyncMode
}

func (*BuilderWrapper) AuditError added in v0.1.155

func (s *BuilderWrapper) AuditError(err error) (*builderv0.AuditResponse, error)

func (*BuilderWrapper) AuditErrorf added in v0.1.155

func (s *BuilderWrapper) AuditErrorf(err error, msg string, args ...any) (*builderv0.AuditResponse, error)

func (*BuilderWrapper) AuditResponse added in v0.1.155

func (s *BuilderWrapper) AuditResponse(findings []*builderv0.AuditFinding, outdated []*builderv0.OutdatedDep, tool, language string) (*builderv0.AuditResponse, error)

AuditResponse builds a successful AuditResponse. State is CLEAN if findings is empty, FINDINGS otherwise. Tool/language identify the scanner used so the CLI can render "[govulncheck+go list -u] go-grpc/api" in mixed-workspace audits.

func (*BuilderWrapper) BuildError added in v0.1.20

func (s *BuilderWrapper) BuildError(err error) (*builderv0.BuildResponse, error)

func (*BuilderWrapper) BuildResponse added in v0.1.20

func (s *BuilderWrapper) BuildResponse() (*builderv0.BuildResponse, error)

func (*BuilderWrapper) CreateError added in v0.1.20

func (s *BuilderWrapper) CreateError(err error) (*builderv0.CreateResponse, error)

func (*BuilderWrapper) CreateErrorf added in v0.1.89

func (s *BuilderWrapper) CreateErrorf(err error, msg string, args ...any) (*builderv0.CreateResponse, error)

func (*BuilderWrapper) CreateKubernetesBase added in v0.1.74

func (s *BuilderWrapper) CreateKubernetesBase(_ context.Context, env *basev0.Environment, namespace string, builderContext *builderv0.DockerBuildContext) (*DeploymentBase, error)

func (*BuilderWrapper) CreateResponse added in v0.1.20

func (s *BuilderWrapper) CreateResponse(ctx context.Context, settings any) (*builderv0.CreateResponse, error)

func (*BuilderWrapper) DeployError added in v0.1.20

func (s *BuilderWrapper) DeployError(err error) (*builderv0.DeploymentResponse, error)

func (*BuilderWrapper) DeployResponse added in v0.1.20

func (s *BuilderWrapper) DeployResponse() (*builderv0.DeploymentResponse, error)

func (*BuilderWrapper) DockerBuildRequest added in v0.1.74

func (*BuilderWrapper) GenerateGenericKustomize added in v0.1.60

func (s *BuilderWrapper) GenerateGenericKustomize(ctx context.Context, fs embed.FS, k *builderv0.KubernetesDeployment, base *DeploymentBase, params any) error

func (*BuilderWrapper) InitError added in v0.1.20

func (s *BuilderWrapper) InitError(err error) (*builderv0.InitResponse, error)

func (*BuilderWrapper) InitErrorf added in v0.1.89

func (s *BuilderWrapper) InitErrorf(err error, msg string, args ...any) (*builderv0.InitResponse, error)

func (*BuilderWrapper) InitResponse added in v0.1.20

func (s *BuilderWrapper) InitResponse() (*builderv0.InitResponse, error)

func (*BuilderWrapper) KubernetesDeploymentRequest added in v0.1.74

func (s *BuilderWrapper) KubernetesDeploymentRequest(_ context.Context, req *builderv0.DeploymentRequest) (*builderv0.KubernetesDeployment, error)

func (*BuilderWrapper) KustomizeDeploy added in v0.1.74

func (s *BuilderWrapper) KustomizeDeploy(ctx context.Context, env *basev0.Environment, req *builderv0.KubernetesDeployment, fs embed.FS, params any) error

func (*BuilderWrapper) LoadError added in v0.1.20

func (s *BuilderWrapper) LoadError(err error) (*builderv0.LoadResponse, error)

func (*BuilderWrapper) LoadErrorf added in v0.1.89

func (s *BuilderWrapper) LoadErrorf(err error, msg string, args ...any) (*builderv0.LoadResponse, error)

func (*BuilderWrapper) LoadResponse added in v0.1.20

func (s *BuilderWrapper) LoadResponse() (*builderv0.LoadResponse, error)

func (*BuilderWrapper) LogDeployRequest added in v0.1.64

func (s *BuilderWrapper) LogDeployRequest(req *builderv0.DeploymentRequest, log wool.LogFunc)

func (*BuilderWrapper) LogInitRequest added in v0.1.64

func (s *BuilderWrapper) LogInitRequest(req *builderv0.InitRequest)

func (*BuilderWrapper) SyncError added in v0.1.20

func (s *BuilderWrapper) SyncError(err error) (*builderv0.SyncResponse, error)

func (*BuilderWrapper) SyncResponse added in v0.1.20

func (s *BuilderWrapper) SyncResponse() (*builderv0.SyncResponse, error)

func (*BuilderWrapper) UpdateError added in v0.1.50

func (s *BuilderWrapper) UpdateError(err error) (*builderv0.UpdateResponse, error)

func (*BuilderWrapper) UpdateResponse added in v0.1.50

func (s *BuilderWrapper) UpdateResponse() (*builderv0.UpdateResponse, error)

func (*BuilderWrapper) UpgradeError added in v0.1.155

func (s *BuilderWrapper) UpgradeError(err error) (*builderv0.UpgradeResponse, error)

func (*BuilderWrapper) UpgradeErrorf added in v0.1.155

func (s *BuilderWrapper) UpgradeErrorf(err error, msg string, args ...any) (*builderv0.UpgradeResponse, error)

func (*BuilderWrapper) UpgradeResponse added in v0.1.155

func (s *BuilderWrapper) UpgradeResponse(changes []*builderv0.UpgradeChange, lockfileDiff string) (*builderv0.UpgradeResponse, error)

UpgradeResponse builds a successful UpgradeResponse. State is NOOP if no changes were applied (or would be, in dry-run), SUCCESS otherwise.

func (*BuilderWrapper) WithDockerImages added in v0.1.74

func (s *BuilderWrapper) WithDockerImages(ims ...*resources.DockerImage)

type CodeAgent added in v0.1.155

type CodeAgent struct {
	codev0.CodeClient
	Agent       *resources.Agent
	ProcessInfo *manager.ProcessInfo
}

CodeAgent is the client-side wrapper for the Code gRPC service.

func NewCodeAgentClient added in v0.1.155

func NewCodeAgentClient(conn *grpc.ClientConn) *CodeAgent

NewCodeAgentClient creates a CodeAgent from an existing gRPC connection.

type CodeServer added in v0.1.155

type CodeServer struct {
	codev0.UnimplementedCodeServer
}

CodeServer is embedded by plugin code types to satisfy the gRPC CodeServer interface. Plugins override methods they implement.

type Command added in v0.1.155

type Command struct {
	Definition *agentv0.CommandDefinition
	Handler    CommandHandler
}

Command pairs a definition with its handler.

type CommandHandler added in v0.1.155

type CommandHandler func(ctx context.Context, args []string) (string, error)

CommandHandler is a function that executes a registered command.

type CommandRegistry added in v0.1.155

type CommandRegistry struct {
	// contains filtered or unexported fields
}

CommandRegistry holds registered commands for an agent.

func NewCommandRegistry added in v0.1.155

func NewCommandRegistry() *CommandRegistry

NewCommandRegistry creates an empty command registry.

func (*CommandRegistry) ListCommands added in v0.1.155

func (r *CommandRegistry) ListCommands() []*agentv0.CommandDefinition

ListCommands returns all registered command definitions.

func (*CommandRegistry) Register added in v0.1.155

func (r *CommandRegistry) Register(def *agentv0.CommandDefinition, handler CommandHandler)

Register adds a command to the registry.

func (*CommandRegistry) Run added in v0.1.155

func (r *CommandRegistry) Run(ctx context.Context, name string, args []string) (string, error)

Run executes a command by name.

type DeploymentBase added in v0.1.20

type DeploymentBase struct {
	*Information
	Sha         string
	Namespace   string
	Environment *resources.Environment
	Image       *resources.DockerImage
	Replicas    int

	// Specialization
	Parameters any
}

type DeploymentParameters added in v0.1.60

type DeploymentParameters struct {
	ConfigMap  EnvironmentMap
	SecretMap  EnvironmentMap
	Parameters any
}

type DeploymentWrapper added in v0.1.20

type DeploymentWrapper struct {
	*DeploymentBase
	Deployment any
}

type EnvironmentMap added in v0.1.33

type EnvironmentMap map[string]string

func EnvsAsConfigMapData added in v0.1.33

func EnvsAsConfigMapData(envs ...*resources.EnvironmentVariable) (EnvironmentMap, error)

func EnvsAsSecretData added in v0.1.33

func EnvsAsSecretData(envs ...*resources.EnvironmentVariable) (EnvironmentMap, error)

type Information added in v0.0.26

type Information struct {
	Service *resources.ServiceWithCase
	Module  *resources.ModuleWithCase
	Agent   *resources.Agent
}

type InformationStatus added in v0.0.26

type InformationStatus struct {
	Load  *runtimev0.LoadStatus
	Init  *runtimev0.InitStatus
	Start *runtimev0.StartStatus

	DesiredState *runtimev0.DesiredState
}

type Parameters added in v0.1.60

type Parameters struct {
	Values map[string]string
}

type RuntimeAgent added in v0.0.51

type RuntimeAgent struct {
	runtimev0.RuntimeClient
	Agent       *resources.Agent
	ProcessInfo *manager.ProcessInfo

	// Some services support re-init without restarting.
	HotReload bool
}

RuntimeAgent is the client-side wrapper for the Runtime gRPC service.

func NewRuntimeAgentClient added in v0.1.155

func NewRuntimeAgentClient(conn *grpc.ClientConn) *RuntimeAgent

NewRuntimeAgentClient creates a RuntimeAgent from an existing gRPC connection.

type RuntimeServer added in v0.0.26

type RuntimeServer struct {
	runtimev0.UnimplementedRuntimeServer
}

RuntimeServer is embedded by plugin runtime types to satisfy the gRPC RuntimeServer interface. Plugins override methods they implement.

type RuntimeWrapper added in v0.0.72

type RuntimeWrapper struct {
	*Base

	RuntimeContext *basev0.RuntimeContext

	RuntimeConfigurations []*basev0.Configuration

	LoadStatus    *runtimev0.LoadStatus
	InitStatus    *runtimev0.InitStatus
	StartStatus   *runtimev0.StartStatus
	StopStatus    *runtimev0.StopStatus
	DestroyStatus *runtimev0.DestroyStatus

	BuildStatus *runtimev0.BuildStatus
	TestStatus  *runtimev0.TestStatus
	LintStatus  *runtimev0.LintStatus

	DesiredState *runtimev0.DesiredState

	sync.RWMutex
}

func (*RuntimeWrapper) BuildError added in v0.1.155

func (s *RuntimeWrapper) BuildError(err error) (*runtimev0.BuildResponse, error)

func (*RuntimeWrapper) BuildErrorf added in v0.1.155

func (s *RuntimeWrapper) BuildErrorf(err error, msg string, args ...any) (*runtimev0.BuildResponse, error)

func (*RuntimeWrapper) BuildResponse added in v0.1.155

func (s *RuntimeWrapper) BuildResponse(output string) (*runtimev0.BuildResponse, error)

func (*RuntimeWrapper) DesiredInit added in v0.1.20

func (s *RuntimeWrapper) DesiredInit()

func (*RuntimeWrapper) DesiredLoad added in v0.1.20

func (s *RuntimeWrapper) DesiredLoad()

func (*RuntimeWrapper) DesiredStart added in v0.1.20

func (s *RuntimeWrapper) DesiredStart()

func (*RuntimeWrapper) DestroyError added in v0.1.89

func (s *RuntimeWrapper) DestroyError(err error) (*runtimev0.DestroyResponse, error)

func (*RuntimeWrapper) DestroyResponse added in v0.1.89

func (s *RuntimeWrapper) DestroyResponse() (*runtimev0.DestroyResponse, error)

func (*RuntimeWrapper) InformationResponse added in v0.0.75

func (*RuntimeWrapper) InitError added in v0.0.72

func (s *RuntimeWrapper) InitError(err error) (*runtimev0.InitResponse, error)

func (*RuntimeWrapper) InitErrorf added in v0.1.89

func (s *RuntimeWrapper) InitErrorf(err error, msg string, args ...any) (*runtimev0.InitResponse, error)

func (*RuntimeWrapper) InitResponse added in v0.0.72

func (s *RuntimeWrapper) InitResponse() (*runtimev0.InitResponse, error)

func (*RuntimeWrapper) IsContainerRuntime added in v0.1.89

func (s *RuntimeWrapper) IsContainerRuntime() bool

func (*RuntimeWrapper) IsNativeRuntime added in v0.1.155

func (s *RuntimeWrapper) IsNativeRuntime() bool

func (*RuntimeWrapper) IsNixRuntime added in v0.1.155

func (s *RuntimeWrapper) IsNixRuntime() bool

func (*RuntimeWrapper) LintError added in v0.1.155

func (s *RuntimeWrapper) LintError(err error) (*runtimev0.LintResponse, error)

func (*RuntimeWrapper) LintErrorf added in v0.1.155

func (s *RuntimeWrapper) LintErrorf(err error, msg string, args ...any) (*runtimev0.LintResponse, error)

func (*RuntimeWrapper) LintResponse added in v0.1.155

func (s *RuntimeWrapper) LintResponse(output string) (*runtimev0.LintResponse, error)

func (*RuntimeWrapper) LoadError added in v0.0.72

func (s *RuntimeWrapper) LoadError(err error) (*runtimev0.LoadResponse, error)

func (*RuntimeWrapper) LoadErrorf added in v0.1.89

func (s *RuntimeWrapper) LoadErrorf(err error, msg string, args ...any) (*runtimev0.LoadResponse, error)

func (*RuntimeWrapper) LoadResponse added in v0.0.72

func (s *RuntimeWrapper) LoadResponse() (*runtimev0.LoadResponse, error)

func (*RuntimeWrapper) LogInitRequest added in v0.1.63

func (s *RuntimeWrapper) LogInitRequest(req *runtimev0.InitRequest)

func (*RuntimeWrapper) LogLoadRequest added in v0.1.89

func (s *RuntimeWrapper) LogLoadRequest(req *runtimev0.LoadRequest)

func (*RuntimeWrapper) LogStartRequest added in v0.1.64

func (s *RuntimeWrapper) LogStartRequest(req *runtimev0.StartRequest)

func (*RuntimeWrapper) MarkRunnerExited added in v0.1.155

func (s *RuntimeWrapper) MarkRunnerExited(err error)

MarkRunnerExited records that the underlying runner process exited AFTER a successful Start. Plugins call this from a Wait-on-binary goroutine so the orchestrator's Follow() loop can observe the death (StartStatus → ERROR) and propagate the failure up to `codefly run`.

Without this, fire-and-forget Start spawns leak: the binary dies, the plugin keeps running, codefly never learns, the user has dead children with a still-alive parent. See cli/cmd/run/service.go for the consumer side.

func (*RuntimeWrapper) SetEnvironment added in v0.1.89

func (s *RuntimeWrapper) SetEnvironment(environment *basev0.Environment)

func (*RuntimeWrapper) StartError added in v0.0.72

func (s *RuntimeWrapper) StartError(err error) (*runtimev0.StartResponse, error)

func (*RuntimeWrapper) StartErrorf added in v0.1.89

func (s *RuntimeWrapper) StartErrorf(err error, msg string, args ...any) (*runtimev0.StartResponse, error)

func (*RuntimeWrapper) StartResponse added in v0.0.72

func (s *RuntimeWrapper) StartResponse() (*runtimev0.StartResponse, error)

func (*RuntimeWrapper) StopError added in v0.1.24

func (s *RuntimeWrapper) StopError(err error) (*runtimev0.StopResponse, error)

func (*RuntimeWrapper) StopResponse added in v0.1.24

func (s *RuntimeWrapper) StopResponse() (*runtimev0.StopResponse, error)

func (*RuntimeWrapper) TestError added in v0.1.89

func (s *RuntimeWrapper) TestError(err error) (*runtimev0.TestResponse, error)

func (*RuntimeWrapper) TestErrorf added in v0.1.89

func (s *RuntimeWrapper) TestErrorf(err error, msg string, args ...any) (*runtimev0.TestResponse, error)

func (*RuntimeWrapper) TestResponse added in v0.1.89

func (s *RuntimeWrapper) TestResponse() (*runtimev0.TestResponse, error)

func (*RuntimeWrapper) TestResponseWithResults added in v0.1.155

func (s *RuntimeWrapper) TestResponseWithResults(run, passed, failed, skipped int32, coverage float32, failures []string, err error) (*runtimev0.TestResponse, error)

func (*RuntimeWrapper) WithContext added in v0.1.89

func (s *RuntimeWrapper) WithContext(runtimeContext *basev0.RuntimeContext)

type ServiceAgent added in v0.0.51

type ServiceAgent struct {
	agentv0.AgentClient
	Agent       *resources.Agent
	ProcessInfo *manager.ProcessInfo
}

ServiceAgent is the client-side wrapper for the Agent gRPC service.

func NewServiceAgentClient added in v0.1.155

func NewServiceAgentClient(conn *grpc.ClientConn) *ServiceAgent

NewServiceAgentClient creates a ServiceAgent from an existing gRPC connection.

type TemplateWrapper added in v0.0.26

type TemplateWrapper struct {
	PathSelect shared.PathSelect
	Override   shared.Override
	// contains filtered or unexported fields
}

func WithBuilder added in v0.0.26

func WithBuilder(fs embed.FS) *TemplateWrapper

func WithDeployment added in v0.0.26

func WithDeployment(fs embed.FS, sub string) *TemplateWrapper

func WithFactory added in v0.0.26

func WithFactory(fs embed.FS) *TemplateWrapper

func WithTemplate added in v0.1.20

func WithTemplate(fs embed.FS, from string, to string) *TemplateWrapper

func (*TemplateWrapper) Destination added in v0.1.20

func (wrapper *TemplateWrapper) Destination(s *Base) string

func (*TemplateWrapper) WithDestination added in v0.1.20

func (wrapper *TemplateWrapper) WithDestination(destination string, args ...any) *TemplateWrapper

func (*TemplateWrapper) WithOverride added in v0.1.18

func (wrapper *TemplateWrapper) WithOverride(override shared.Override) *TemplateWrapper

func (*TemplateWrapper) WithPathSelect added in v0.1.20

func (wrapper *TemplateWrapper) WithPathSelect(pathSelect shared.PathSelect) *TemplateWrapper

type WatchConfiguration added in v0.0.26

type WatchConfiguration struct {
	// contains filtered or unexported fields
}

func NewWatchConfiguration added in v0.0.26

func NewWatchConfiguration(dependencies *builders.Dependencies) *WatchConfiguration

Directories

Path Synopsis
Package audit runs language-specific dependency audits on behalf of codefly Builder agents.
Package audit runs language-specific dependency audits on behalf of codefly Builder agents.
Package upgrade applies dependency bumps on behalf of codefly Builder agents.
Package upgrade applies dependency bumps on behalf of codefly Builder agents.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL