command

package
v0.33.0 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: Apache-2.0 Imports: 52 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ConfigWizardCmd = &cli.Command{
	Name:  "config-wizard",
	Usage: "Run the web-based config wizard",
	Description: `Start a local web UI that generates a knot.toml in an embedded TOML editor.

The wizard always starts. When no config exists yet, the editor's Write button
saves straight to disk; when a config already exists, Write is disabled and the
generated text is shown for manual copy / merge.

Listens on 127.0.0.1 by default; bind a different address with --listen. Use
--config to target a non-default output path.`,
	MaxArgs: cli.NoArgs,
	Flags: []cli.Flag{
		&cli.IntFlag{
			Name:         "port",
			Usage:        "TCP port to serve the wizard web UI on.",
			DefaultValue: 8080,
		},
		&cli.StringFlag{
			Name:         "listen",
			Usage:        "Address to bind the wizard web UI to. Defaults to loopback.",
			DefaultValue: "127.0.0.1",
		},
	},
	Run: func(ctx context.Context, cmd *cli.Command) error {
		addr := fmt.Sprintf("%s:%d", cmd.GetString("listen"), cmd.GetInt("port"))

		sigCtx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
		defer stop()

		return configwizard.Serve(sigCtx, addr, cmd.GetString("config"))
	},
}
View Source
var ConnectCmd = &cli.Command{
	Name:        "connect",
	Usage:       "Connect to server",
	Description: "Authenticate the client with a remote server and save the server address and access key.",
	Arguments: []cli.Argument{
		&cli.StringArg{
			Name:     "server",
			Usage:    "The server to connect to",
			Required: true,
		},
	},
	MaxArgs: cli.NoArgs,
	Flags: []cli.Flag{
		&cli.BoolFlag{
			Name:  "use-web-auth",
			Usage: "If given then authorization will be done via the web interface.",
		},
		&cli.BoolFlag{
			Name:         "tls-skip-verify",
			Usage:        "Skip TLS verification when talking to server.",
			ConfigPath:   []string{"tls.skip_verify"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TLS_SKIP_VERIFY"},
			DefaultValue: true,
			Global:       true,
		},
		&cli.StringFlag{
			Name:    "username",
			Aliases: []string{"u"},
			Usage:   "Username to use for authentication.",
		},
		&cli.StringFlag{
			Name:         "alias",
			Aliases:      []string{"a"},
			Usage:        "The server alias to use to identify the connection.",
			DefaultValue: "default",
		},
	},
	Commands: []*cli.Command{
		connectcmd.ConnectListCmd,
		connectcmd.ConnectDeleteCmd,
	},
	Run: func(ctx context.Context, cmd *cli.Command) error {
		var token string

		server := cmd.GetStringArg("server")

		if !strings.HasPrefix(server, "http://") && !strings.HasPrefix(server, "https://") {
			server = "https://" + server
		}

		fmt.Println("Connecting to server: ", server)

		u, err := url.Parse(server)
		if err != nil {
			fmt.Println("Failed to parse server URL")
			os.Exit(1)
		}

		hostname, err := os.Hostname()
		if err != nil {
			fmt.Println("Failed to get hostname")
			os.Exit(1)
		}

		hostname = "knot client " + hostname

		client, err := apiclient.NewClient(
			server,
			"",
			cmd.GetBool("tls-skip-verify"),
		)
		if err != nil {
			fmt.Println("Failed to create API client:", err)
			os.Exit(1)
		}

		totp, _, err := client.UsingTOTP(context.Background())
		if err != nil {
			fmt.Println("Failed to query server for TOTP")
			os.Exit(1)
		}

		if totp || cmd.GetBool("use-web-auth") {
			u.Path = "/api-tokens/create/" + url.PathEscape(hostname)
			err = util.OpenBrowser(u.String())
			if err != nil {
				fmt.Println("Failed to open server URL, you will need to generate the API token manually")
				os.Exit(1)
			}
			fmt.Print("Enter token: ")
			_, err = fmt.Scanln(&token)
			if err != nil {
				fmt.Println("Failed to read token, you will need to generate the API token manually")
				os.Exit(1)
			}

			client.SetAuthToken(token)
			requireCompatibleServer(client)
		} else {
			username := cmd.GetString("username")
			var password []byte

			if username == "" {
				fmt.Print("Enter email: ")
				_, err = fmt.Scanln(&username)
				if err != nil {
					fmt.Println("Failed to read email address")
					os.Exit(1)
				}
			}

			fmt.Print("Enter password: ")
			password, err = term.ReadPassword(int(syscall.Stdin))
			if err != nil {
				fmt.Println("Failed to read password")
				os.Exit(1)
			}
			fmt.Println()

			if username == "" || string(password) == "" {
				fmt.Println("Username and password must be given")
				os.Exit(1)
			}

			response, _, _ := client.Login(context.Background(), username, string(password), "")
			if response == nil || response.Token == "" {
				fmt.Println("Failed to login")
				os.Exit(1)
			}

			client.UseSessionCookie(true).SetAuthToken(response.Token)

			requireCompatibleServer(client)

			token, _, err = client.CreateToken(context.Background(), hostname, nil)
			if err != nil || token == "" {
				fmt.Println("Failed to create token")
				os.Exit(1)
			}
		}

		alias := cmd.GetString("alias")
		if err := config.SaveConnection(alias, server, token, cmd); err != nil {
			fmt.Println("Failed to save connection:", err)
			os.Exit(1)
		}

		fmt.Println("Successfully connected to server:", server)
		return nil
	},
}
View Source
var GenkeyCmd = &cli.Command{
	Name:        "genkey",
	Usage:       "Generate Encryption Key",
	Description: "Generate an encryption key for encrypting stored variables and cluster communications.",
	MaxArgs:     cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		key := crypt.CreateKey()
		fmt.Println("Encryption Key:", key)
		fmt.Println("")
		return nil
	},
}
View Source
var LegalCmd = &cli.Command{
	Name:        "legal",
	Usage:       "Show legal information",
	Description: "Output all the legal notices.",
	MaxArgs:     cli.NoArgs,
	Run: func(ctx context.Context, cmd *cli.Command) error {
		legal.ShowLicenses()
		return nil
	},
}
View Source
var PingCmd = &cli.Command{
	Name:        "ping",
	Usage:       "Ping the server",
	Description: "Ping the server and display the health and version number.",
	MaxArgs:     cli.NoArgs,
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:    "server",
			Aliases: []string{"s"},
			Usage:   "The address of the remote server to ping.",
			EnvVars: []string{config.CONFIG_ENV_PREFIX + "_SERVER"},
		},
		&cli.StringFlag{
			Name:    "token",
			Aliases: []string{"t"},
			Usage:   "The token to use for authentication.",
			EnvVars: []string{config.CONFIG_ENV_PREFIX + "_TOKEN"},
		},
		&cli.StringFlag{
			Name:         "alias",
			Aliases:      []string{"a"},
			Usage:        "The server alias to use.",
			DefaultValue: "default",
		},
		&cli.BoolFlag{
			Name:         "tls-skip-verify",
			Usage:        "Skip TLS verification when talking to server.",
			ConfigPath:   []string{"tls.skip_verify"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TLS_SKIP_VERIFY"},
			DefaultValue: true,
		},
	},
	Run: func(ctx context.Context, cmd *cli.Command) error {
		alias := cmd.GetString("alias")

		cfg := config.GetServerAddr(alias, cmd)
		fmt.Println("Pinging server: ", cfg.HttpServer)

		client, err := apiclient.NewClient(
			cfg.HttpServer,
			cfg.ApiToken,
			cmd.GetBool("tls-skip-verify"),
		)
		if err != nil {
			return fmt.Errorf("Failed to create API client: %w", err)
		}

		version, err := client.Ping(ctx)
		if err != nil {
			return fmt.Errorf("Failed to ping server: %w", err)
		}

		fmt.Println("\nServer is healthy")
		fmt.Println("Version: ", version.Version)
		fmt.Println("Zone: ", version.Zone)

		return nil
	},
}
View Source
var ScaffoldCmd = &cli.Command{
	Name:        "scaffold",
	Usage:       "Generate configuration files",
	Description: "Generates example configuration files for use with knot.",
	MaxArgs:     cli.NoArgs,
	Flags: []cli.Flag{
		&cli.BoolFlag{
			Name:       "server",
			Usage:      "Generate a server configuration file",
			ConfigPath: []string{"scaffold.server"},
		},
		&cli.BoolFlag{
			Name:       "client",
			Usage:      "Generate a client configuration file",
			ConfigPath: []string{"scaffold.client"},
		},
		&cli.BoolFlag{
			Name:       "agent",
			Usage:      "Generate an agent configuration file",
			ConfigPath: []string{"scaffold.agent"},
		},
		&cli.BoolFlag{
			Name:       "nomad",
			Usage:      "Generate a nomad job file",
			ConfigPath: []string{"scaffold.nomad"},
		},
		&cli.BoolFlag{
			Name:       "system-prompt",
			Usage:      "Generate the internal system prompt",
			ConfigPath: []string{"scaffold.system_prompt"},
		},
	},
	Run: func(ctx context.Context, cmd *cli.Command) error {
		any := false

		if cmd.GetBool("server") {
			fmt.Println(scaffold.ServerScaffold)
			any = true
		}
		if cmd.GetBool("client") {
			fmt.Println(scaffold.ClientScaffold)
			any = true
		}
		if cmd.GetBool("agent") {
			fmt.Println(scaffold.AgentScaffold)
			any = true
		}
		if cmd.GetBool("nomad") {
			fmt.Println(scaffold.NomadScaffold)
			any = true
		}
		if cmd.GetBool("system-prompt") {
			fmt.Println(scaffold.GetSystemPromptScaffold())
			any = true
		}

		if !any {
			cmd.ShowHelp()
		}
		return nil
	},
}
View Source
var ServerCmd = &cli.Command{
	Name:        "server",
	Usage:       "Start the knot server",
	Description: "Start the knot server and listen for incoming connections.",
	MaxArgs:     cli.NoArgs,
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:         "listen",
			Aliases:      []string{"l"},
			Usage:        "The address to listen on.",
			ConfigPath:   []string{"server.listen"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_LISTEN"},
			DefaultValue: ":3000",
		},
		&cli.StringFlag{
			Name:         "listen-agent",
			Usage:        "The address to listen on for agent connections.",
			ConfigPath:   []string{"server.listen_agent"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_LISTEN_AGENT"},
			DefaultValue: "127.0.0.1:3010",
		},
		&cli.StringFlag{
			Name:         "listen-tunnel",
			Usage:        "The address to listen on for tunnel connections.",
			ConfigPath:   []string{"server.listen_tunnel"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_LISTEN_TUNNEL"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "url",
			Aliases:      []string{"u"},
			Usage:        "The URL to use for the server.",
			ConfigPath:   []string{"server.url"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_URL"},
			DefaultValue: "http://127.0.0.1:3000",
		},
		&cli.StringFlag{
			Name:         "tunnel-server",
			Usage:        "The URL for the tunnel client to connect to the individual server.",
			ConfigPath:   []string{"server.tunnel_server"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TUNNEL_SERVER"},
			DefaultValue: "",
		},
		&cli.BoolFlag{
			Name:         "terminal-webgl",
			Usage:        "Enable WebGL terminal renderer.",
			ConfigPath:   []string{"server.terminal.webgl"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_WEBGL"},
			DefaultValue: true,
		},
		&cli.StringFlag{
			Name:         "download-path",
			Usage:        "The path to serve download files from if set.",
			ConfigPath:   []string{"server.download_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_DOWNLOAD_PATH"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "wildcard-domain",
			Usage:        "The wildcard domain to use for proxying to spaces.",
			ConfigPath:   []string{"server.wildcard_domain"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_WILDCARD_DOMAIN"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "encrypt",
			Usage:        "The encryption key to use for encrypting stored variables.",
			ConfigPath:   []string{"server.encrypt"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ENCRYPT"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "agent-endpoint",
			Usage:        "The address agents should use to talk to the server.",
			ConfigPath:   []string{"server.agent_endpoint"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AGENT_ENDPOINT"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:       "zone",
			Usage:      "The zone of the server.",
			ConfigPath: []string{"server.zone"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_ZONE"},
		},
		&cli.StringFlag{
			Name:       "hostname",
			Usage:      "The hostname to advertise to other servers (defaults to system hostname).",
			ConfigPath: []string{"server.hostname"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_HOSTNAME"},
		},
		&cli.StringFlag{
			Name:         "html-path",
			Usage:        "The optional path to the html files to serve.",
			ConfigPath:   []string{"server.html_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_HTML_PATH"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "template-path",
			Usage:        "The optional path to the template files to serve.",
			ConfigPath:   []string{"server.template_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TEMPLATE_PATH"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "agent-path",
			Usage:        "The optional path to the agent files to serve.",
			ConfigPath:   []string{"server.agent_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AGENT_PATH"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "package-path",
			Usage:        "The optional path to the scriptling packages to serve.",
			ConfigPath:   []string{"server.package_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_PACKAGE_PATH"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "timezone",
			Usage:        "The timezone to use for the server.",
			ConfigPath:   []string{"server.timezone"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TIMEZONE"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "tunnel-domain",
			Usage:        "The domain to use for tunnel connections.",
			ConfigPath:   []string{"server.tunnel_domain"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TUNNEL_DOMAIN"},
			DefaultValue: "",
		},
		&cli.IntFlag{
			Name:         "audit-retention",
			Usage:        "The number of days to keep audit logs.",
			ConfigPath:   []string{"server.audit_retention", "server.audit.retention"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUDIT_RETENTION"},
			DefaultValue: 90,
		},
		&cli.StringFlag{
			Name:         "audit-routing",
			Usage:        "Audit log routing: internal, external, or both.",
			ConfigPath:   []string{"server.audit_routing", "server.audit.routing"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUDIT_ROUTING"},
			DefaultValue: "internal",
		},
		&cli.BoolFlag{
			Name:         "audit-file-operations",
			Usage:        "Audit space file read, write and copy operations (path and byte count only, never content). Off by default — noisy for local development.",
			ConfigPath:   []string{"server.audit_file_operations", "server.audit.file_operations"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUDIT_FILE_OPERATIONS"},
			DefaultValue: false,
		},
		&cli.BoolFlag{
			Name:         "audit-space-sessions",
			Usage:        "Audit interactive space session opens (web terminal, SSH, VS Code tunnel). Off by default — noisy for local development.",
			ConfigPath:   []string{"server.audit_space_sessions", "server.audit.space_sessions"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUDIT_SPACE_SESSIONS"},
			DefaultValue: false,
		},
		&cli.StringFlag{
			Name:         "audit-stream",
			Usage:        "Stream label used when routing audit logs to the external log driver.",
			ConfigPath:   []string{"server.audit_stream", "server.audit.stream"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUDIT_STREAM"},
			DefaultValue: "knot_audit",
		},
		&cli.IntFlag{
			Name:         "mcp-tool-timeout",
			Usage:        "The maximum execution time in seconds for MCP tool calls (allows for LLM operations with tool calling).",
			ConfigPath:   []string{"server.mcp_tool_timeout"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MCP_TOOL_TIMEOUT"},
			DefaultValue: 180,
		},
		&cli.StringSliceFlag{
			Name:       "script-fs-allowed-paths",
			Usage:      "Comma-separated list of directory paths server-side scripts (MCP tools, event sinks) may access via the fs library. The fs library is not registered on the server unless this is set.",
			ConfigPath: []string{"server.script_fs_allowed_paths"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_SCRIPT_FS_ALLOWED_PATHS"},
		},
		&cli.BoolFlag{
			Name:         "disable-space-create",
			Usage:        "Disable the ability to create spaces.",
			ConfigPath:   []string{"server.disable_space_create"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_DISABLE_SPACE_CREATE"},
			DefaultValue: false,
		},
		&cli.BoolFlag{
			Name:         "auth-ip-rate-limiting",
			Usage:        "Enable IP rate limiting of authentication.",
			ConfigPath:   []string{"server.auth_ip_rate_limiting"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUTH_IP_RATE_LIMITING"},
			DefaultValue: true,
		},
		&cli.IntFlag{
			Name:         "auth-rate-limit-attempts",
			Usage:        "Failed login attempts per IP/email before auth is blocked.",
			ConfigPath:   []string{"server.auth_rate_limit_attempts"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUTH_RATE_LIMIT_ATTEMPTS"},
			DefaultValue: 10,
		},
		&cli.IntFlag{
			Name:         "auth-rate-limit-window",
			Usage:        "Window in seconds over which failed login attempts are counted.",
			ConfigPath:   []string{"server.auth_rate_limit_window"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUTH_RATE_LIMIT_WINDOW"},
			DefaultValue: 60,
		},
		&cli.IntFlag{
			Name:         "auth-rate-limit-block",
			Usage:        "How long in seconds auth stays blocked after the failed login limit trips.",
			ConfigPath:   []string{"server.auth_rate_limit_block"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_AUTH_RATE_LIMIT_BLOCK"},
			DefaultValue: 300,
		},
		&cli.StringFlag{
			Name:         "public-files-path",
			Usage:        "The path to the a directory to serve as /public-files.",
			ConfigPath:   []string{"server.public_files_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_PUBLIC_FILES_PATH"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "private-files-path",
			Usage:        "The path to the a directory to serve as /private-files.",
			ConfigPath:   []string{"server.private_files_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_PRIVATE_FILES_PATH"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "mcp-tools-path",
			Usage:        "Path to mcp-tools directory (overrides embedded tools).",
			ConfigPath:   []string{"server.mcp_tools_path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MCP_TOOLS_PATH"},
			DefaultValue: "",
		},
		&cli.StringSliceFlag{
			Name:       "mcp-disable-builtin-tools",
			Usage:      "Comma-separated list of built-in tool names to disable.",
			ConfigPath: []string{"server.mcp.disable_builtin_tools"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_MCP_DISABLE_BUILTIN_TOOLS"},
		},

		&cli.BoolFlag{
			Name:         "hide-support-links",
			Usage:        "Hide the support links in the UI.",
			ConfigPath:   []string{"server.ui.hide_support_links"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_HIDE_SUPPORT_LINKS"},
			DefaultValue: false,
		},
		&cli.BoolFlag{
			Name:         "hide-api-tokens",
			Usage:        "Hide the API tokens menu item in the UI.",
			ConfigPath:   []string{"server.ui.hide_api_tokens"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_HIDE_API_TOKENS"},
			DefaultValue: false,
		},
		&cli.BoolFlag{
			Name:         "enable-gravatar",
			Usage:        "Enable Gravatar support in the UI.",
			ConfigPath:   []string{"server.ui.enable_gravatar"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ENABLE_GRAVATAR"},
			DefaultValue: true,
		},
		&cli.StringSliceFlag{
			Name:       "icons",
			Usage:      "File defining icons for use with templates and spaces, can be given multiple times.",
			ConfigPath: []string{"server.ui.icons"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_ICONS"},
		},
		&cli.BoolFlag{
			Name:         "enable-builtin-icons",
			Usage:        "Enable the use of the built-in icons.",
			ConfigPath:   []string{"server.ui.enable_builtin_icons"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ENABLE_BUILTIN_ICONS"},
			DefaultValue: true,
		},
		&cli.StringFlag{
			Name:         "logo-url",
			Usage:        "The URL to the logo to use in the UI.",
			ConfigPath:   []string{"server.ui.logo_url"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_LOGO_URL"},
			DefaultValue: "",
		},
		&cli.BoolFlag{
			Name:         "logo-invert",
			Usage:        "Invert the logo colors in the UI for dark mode.",
			ConfigPath:   []string{"server.ui.logo_invert"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_LOGO_INVERT"},
			DefaultValue: false,
		},

		&cli.StringFlag{
			Name:         "cluster-key",
			Usage:        "The shared cluster key.",
			ConfigPath:   []string{"server.cluster.key"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CLUSTER_KEY"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "cluster-advertise-addr",
			Usage:        "The address to advertise to other servers.",
			ConfigPath:   []string{"server.cluster.advertise_addr"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CLUSTER_ADVERTISE_ADDR"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "cluster-bind-addr",
			Usage:        "The address to bind to for cluster communication.",
			ConfigPath:   []string{"server.cluster.bind_addr"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CLUSTER_BIND_ADDR"},
			DefaultValue: "",
		},
		&cli.StringSliceFlag{
			Name:       "cluster-peer",
			Usage:      "The addresses of the other servers in the cluster, can be given multiple times.",
			ConfigPath: []string{"server.cluster.peers"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_CLUSTER_PEERS"},
		},
		&cli.BoolFlag{
			Name:         "allow-leaf-nodes",
			Usage:        "Allow leaf nodes to connect to the cluster.",
			ConfigPath:   []string{"server.cluster.allow_leaf_nodes"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ALLOW_LEAF_NODES"},
			DefaultValue: true,
		},
		&cli.IntFlag{
			Name:         "min-cluster-size",
			Usage:        "Minimum nodes required for leader election quorum; set to the majority of the smallest zone (2 for production, 1 for single-machine testing).",
			ConfigPath:   []string{"server.cluster.min_cluster_size"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CLUSTER_MIN_CLUSTER_SIZE"},
			DefaultValue: 1,
		},
		&cli.BoolFlag{
			Name:         "cluster-compression",
			Usage:        "Enable compression for cluster communication.",
			ConfigPath:   []string{"server.cluster.compression"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CLUSTER_COMPRESSION"},
			DefaultValue: true,
		},
		&cli.BoolFlag{
			Name:       "cluster-tcp-only",
			Usage:      "Disable UDP and use TCP only for cluster communication.",
			ConfigPath: []string{"server.cluster.tcp_only"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_CLUSTER_TCP_ONLY"},
		},

		&cli.StringFlag{
			Name:         "origin-server",
			Usage:        "The address of the origin server.",
			ConfigPath:   []string{"server.origin.server"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ORIGIN_SERVER"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "origin-token",
			Usage:        "The token to use for the origin server.",
			ConfigPath:   []string{"server.origin.token"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ORIGIN_TOKEN"},
			DefaultValue: "",
		},

		&cli.BoolFlag{
			Name:         "enable-totp",
			Usage:        "Enable TOTP for users.",
			ConfigPath:   []string{"server.totp.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_ENABLE_TOTP"},
			DefaultValue: false,
		},
		&cli.IntFlag{
			Name:         "totp-window",
			Usage:        "The number of time steps (30 seconds) to check for TOTP codes.",
			ConfigPath:   []string{"server.totp.window"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TOTP_WINDOW"},
			DefaultValue: 1,
		},
		&cli.StringFlag{
			Name:         "totp-issuer",
			Usage:        "The issuer to use for TOTP codes.",
			ConfigPath:   []string{"server.totp.issuer"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TOTP_ISSUER"},
			DefaultValue: "Knot",
		},

		&cli.StringFlag{
			Name:         "cert-file",
			Usage:        "The file with the PEM encoded certificate to use for the server.",
			ConfigPath:   []string{"server.tls.cert_file"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CERT_FILE"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "key-file",
			Usage:        "The file with the PEM encoded key to use for the server.",
			ConfigPath:   []string{"server.tls.key_file"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_KEY_FILE"},
			DefaultValue: "",
		},
		&cli.BoolFlag{
			Name:         "use-tls",
			Usage:        "Enable TLS.",
			ConfigPath:   []string{"server.tls.use_tls"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_USE_TLS"},
			DefaultValue: true,
		},
		&cli.BoolFlag{
			Name:         "tls-skip-verify",
			Usage:        "Skip TLS verification when talking to agents.",
			ConfigPath:   []string{"tls.skip_verify"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_TLS_SKIP_VERIFY"},
			DefaultValue: true,
		},

		&cli.StringFlag{
			Name:         "nomad-addr",
			Usage:        "The address of the Nomad server.",
			ConfigPath:   []string{"server.nomad.addr"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_NOMAD_ADDR"},
			DefaultValue: "http://127.0.0.1:4646",
		},
		&cli.StringFlag{
			Name:         "nomad-token",
			Usage:        "The token to use for Nomad API requests.",
			ConfigPath:   []string{"server.nomad.token"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_NOMAD_TOKEN"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "nomad-dc",
			Usage:        "The Nomad datacenter to expose as ${{ .nomad.dc }} in templates and to pre-fill in new Nomad jobs. Defaults to the NOMAD_DC environment variable (set automatically when knot runs as a Nomad job).",
			ConfigPath:   []string{"server.nomad.dc"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_NOMAD_DC"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "nomad-region",
			Usage:        "The Nomad region to expose as ${{ .nomad.region }} in templates and to pre-fill in new Nomad jobs. Defaults to the NOMAD_REGION environment variable (set automatically when knot runs as a Nomad job).",
			ConfigPath:   []string{"server.nomad.region"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_NOMAD_REGION"},
			DefaultValue: "",
		},

		&cli.BoolFlag{
			Name:         "mysql-enabled",
			Usage:        "Enable MySQL database backend.",
			ConfigPath:   []string{"server.mysql.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_ENABLED"},
			DefaultValue: false,
		},
		&cli.StringFlag{
			Name:         "mysql-host",
			Usage:        "The MySQL host to connect to.",
			ConfigPath:   []string{"server.mysql.host"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_HOST"},
			DefaultValue: "localhost",
		},
		&cli.IntFlag{
			Name:         "mysql-port",
			Usage:        "The MySQL port to connect to.",
			ConfigPath:   []string{"server.mysql.port"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_PORT"},
			DefaultValue: 3306,
		},
		&cli.StringFlag{
			Name:         "mysql-user",
			Usage:        "The MySQL user to connect as.",
			ConfigPath:   []string{"server.mysql.user"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_USER"},
			DefaultValue: "root",
		},
		&cli.StringFlag{
			Name:         "mysql-password",
			Usage:        "The MySQL password to use.",
			ConfigPath:   []string{"server.mysql.password"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_PASSWORD"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "mysql-database",
			Usage:        "The MySQL database to use.",
			ConfigPath:   []string{"server.mysql.database"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_DATABASE"},
			DefaultValue: "knot",
		},
		&cli.IntFlag{
			Name:         "mysql-connection-max-idle",
			Usage:        "The maximum number of idle connections in the connection pool.",
			ConfigPath:   []string{"server.mysql.connection_max_idle"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_CONNECTION_MAX_IDLE"},
			DefaultValue: 10,
		},
		&cli.IntFlag{
			Name:         "mysql-connection-max-open",
			Usage:        "The maximum number of open connections to the database.",
			ConfigPath:   []string{"server.mysql.connection_max_open"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_CONNECTION_MAX_OPEN"},
			DefaultValue: 100,
		},
		&cli.IntFlag{
			Name:         "mysql-connection-max-lifetime",
			Usage:        "The maximum amount of time in minutes a connection may be reused.",
			ConfigPath:   []string{"server.mysql.connection_max_lifetime"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MYSQL_CONNECTION_MAX_LIFETIME"},
			DefaultValue: 5,
		},

		&cli.BoolFlag{
			Name:         "badgerdb-enabled",
			Usage:        "Enable BadgerDB database backend.",
			ConfigPath:   []string{"server.badgerdb.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_BADGERDB_ENABLED"},
			DefaultValue: false,
		},
		&cli.StringFlag{
			Name:         "badgerdb-path",
			Usage:        "The path to the BadgerDB database.",
			ConfigPath:   []string{"server.badgerdb.path"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_BADGERDB_PATH"},
			DefaultValue: "./badger",
		},

		&cli.BoolFlag{
			Name:         "redis-enabled",
			Usage:        "Enable Redis database backend.",
			ConfigPath:   []string{"server.redis.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_ENABLED"},
			DefaultValue: false,
		},
		&cli.StringSliceFlag{
			Name:         "redis-hosts",
			Usage:        "The redis server(s), can be specified multiple times.",
			ConfigPath:   []string{"server.redis.hosts"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_HOSTS"},
			DefaultValue: []string{"localhost:6379"},
		},
		&cli.StringFlag{
			Name:         "redis-password",
			Usage:        "The password to use for the redis server.",
			ConfigPath:   []string{"server.redis.password"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_PASSWORD"},
			DefaultValue: "",
		},
		&cli.IntFlag{
			Name:         "redis-db",
			Usage:        "The redis database to use.",
			ConfigPath:   []string{"server.redis.db"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_DB"},
			DefaultValue: 0,
		},
		&cli.StringFlag{
			Name:         "redis-master-name",
			Usage:        "The name of the master to use for failover clients.",
			ConfigPath:   []string{"server.redis.master_name"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_MASTER_NAME"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "redis-key-prefix",
			Usage:        "The prefix to use for all keys in the redis database.",
			ConfigPath:   []string{"server.redis.key_prefix"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_REDIS_KEY_PREFIX"},
			DefaultValue: "",
		},

		&cli.StringFlag{
			Name:         "docker-host",
			Usage:        "The Docker host to connect to.",
			ConfigPath:   []string{"server.docker.host"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_DOCKER_HOST"},
			DefaultValue: "unix:///var/run/docker.sock",
		},

		&cli.StringFlag{
			Name:         "podman-host",
			Usage:        "The Podman host to connect to.",
			ConfigPath:   []string{"server.podman.host"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_PODMAN_HOST"},
			DefaultValue: "unix:///var/run/podman.sock",
		},

		&cli.StringSliceFlag{
			Name:         "local-container-runtime-pref",
			Usage:        "Preference order for local container runtimes (docker, podman, apple). First available will be used.",
			ConfigPath:   []string{"server.local_containers.runtime_pref"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_LOCAL_CONTAINERS_RUNTIME_PREF"},
			DefaultValue: []string{"docker", "podman", "apple"},
		},

		&cli.StringFlag{
			Name:         "base-image-registry",
			Usage:        "Default registry prefix for base images referenced by the template spec wizard. Exposed to specs as ${{ .server.base_image_registry }}.",
			ConfigPath:   []string{"server.base_image.registry_url"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_BASE_IMAGE_REGISTRY"},
			DefaultValue: "registry-1.docker.io/paularlott",
		},
		&cli.StringFlag{
			Name:       "base-images-manifest",
			Usage:      "Path to a TOML manifest of base images for the template spec wizard. Defaults to the bundled manifest.",
			ConfigPath: []string{"server.base_image.manifest"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BASE_IMAGES_MANIFEST"},
		},
		&cli.StringFlag{
			Name:       "base-image-registry-user",
			Usage:      "Username for the base image registry. Exposed to specs as ${{ .server.base_image_registry_user }}.",
			ConfigPath: []string{"server.base_image.registry_user"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BASE_IMAGE_REGISTRY_USER"},
		},
		&cli.StringFlag{
			Name:       "base-image-registry-password",
			Usage:      "Password for the base image registry. Exposed to specs as ${{ .server.base_image_registry_password }}.",
			ConfigPath: []string{"server.base_image.registry_password"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_BASE_IMAGE_REGISTRY_PASSWORD"},
		},
		&cli.BoolFlag{
			Name:         "base-images-update-enabled",
			Usage:        "Master gate for fetching the base image manifest from --base-images-update-url. When set, the server fetches once on startup (background) and the admin refresh command is permitted; when unset, no remote fetch happens and `knot admin refresh-base-images` will fail. With --base-images-manifest set, the file is the baseline and a fetched copy overlays it only when newer.",
			ConfigPath:   []string{"server.base_image.update_enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_BASE_IMAGES_UPDATE_ENABLED"},
			DefaultValue: false,
		},
		&cli.StringFlag{
			Name:        "base-images-update-url",
			Usage:       "URL to fetch the base image manifest from. When unset, the default (" + specwizard.DefaultUpdateURL + ") is used unless a manifest file is configured.",
			ConfigPath:  []string{"server.base_image.update_url"},
			EnvVars:     []string{config.CONFIG_ENV_PREFIX + "_BASE_IMAGES_UPDATE_URL"},
			DefaultText: specwizard.DefaultUpdateURL,
		},

		&cli.BoolFlag{
			Name:         "mcp-enabled",
			Usage:        "Enable MCP (Model Context Protocol) server functionality.",
			ConfigPath:   []string{"server.mcp.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_MCP_ENABLED"},
			DefaultValue: false,
		},

		&cli.BoolFlag{
			Name:         "chat-enabled",
			Usage:        "Enable AI chat functionality.",
			ConfigPath:   []string{"server.chat.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_ENABLED"},
			DefaultValue: false,
		},
		&cli.BoolFlag{
			Name:         "chat-openai-endpoints",
			Usage:        "Enable OpenAI-compatible endpoints for external clients.",
			ConfigPath:   []string{"server.chat.openai_endpoints"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_OPENAI_ENDPOINTS"},
			DefaultValue: false,
		},
		&cli.StringFlag{
			Name:         "chat-provider",
			Usage:        "LLM provider for chat functionality (openai, claude, gemini, ollama, mistral, zai).",
			ConfigPath:   []string{"server.chat.provider"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_PROVIDER"},
			DefaultValue: "openai",
		},
		&cli.StringFlag{
			Name:         "chat-api-key",
			Usage:        "API key for chat functionality.",
			ConfigPath:   []string{"server.chat.api_key"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_API_KEY"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "chat-base-url",
			Usage:        "Base URL for chat functionality.",
			ConfigPath:   []string{"server.chat.base_url"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_BASE_URL"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "chat-type",
			Usage:        "AI API type (openai, anthropic, google, ollama). Determines the protocol used to communicate with the LLM.",
			ConfigPath:   []string{"server.chat.type"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_TYPE"},
			DefaultValue: "openai",
		},
		&cli.StringFlag{
			Name:         "chat-openai-api-key",
			Usage:        "Deprecated: use chat-api-key instead.",
			ConfigPath:   []string{"server.chat.openai_api_key"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_OPENAI_API_KEY"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "chat-openai-base-url",
			Usage:        "Deprecated: use chat-base-url instead.",
			ConfigPath:   []string{"server.chat.openai_base_url"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_OPENAI_BASE_URL"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "chat-model",
			Usage:        "OpenAI model to use for chat.",
			ConfigPath:   []string{"server.chat.model"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_MODEL"},
			DefaultValue: "qwen2.5-coder:14b",
		},
		&cli.IntFlag{
			Name:         "chat-max-tokens",
			Usage:        "Maximum tokens for chat responses.",
			ConfigPath:   []string{"server.chat.max_tokens"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_MAX_TOKENS"},
			DefaultValue: 0,
		},
		&cli.Float32Flag{
			Name:         "chat-temperature",
			Usage:        "Temperature for chat responses.",
			ConfigPath:   []string{"server.chat.temperature"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_TEMPERATURE"},
			DefaultValue: 0.1,
		},
		&cli.StringFlag{
			Name:         "chat-system-prompt-file",
			Usage:        "Optional file path for system prompt. If not provided, uses default embedded prompt.",
			ConfigPath:   []string{"server.chat.system_prompt_file"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_SYSTEM_PROMPT_FILE"},
			DefaultValue: "",
		},
		&cli.StringFlag{
			Name:         "chat-reasoning-effort",
			Usage:        "Reasoning effort level for chat responses (low, medium, high).",
			ConfigPath:   []string{"server.chat.reasoning_effort"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_REASONING_EFFORT"},
			DefaultValue: "",
			ValidateFlag: func(c *cli.Command) error {
				value := c.GetString("chat-reasoning-effort")
				if value != "" && value != "none" && value != "low" && value != "medium" && value != "high" {
					return fmt.Errorf("If given, reasoning effort must be one of: none, low, medium, high")
				}
				return nil
			},
		},
		&cli.StringFlag{
			Name:         "chat-ui-style",
			Usage:        "UI style for assistant button (icon or avatar).",
			ConfigPath:   []string{"server.chat.ui_style"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_CHAT_UI_STYLE"},
			DefaultValue: "icon",
			ValidateFlag: func(c *cli.Command) error {
				value := c.GetString("chat-ui-style")
				if value != "" && value != "icon" && value != "avatar" {
					return fmt.Errorf("UI style must be one of: icon, avatar")
				}
				return nil
			},
		},

		&cli.BoolFlag{
			Name:         "dns-enabled",
			Usage:        "Enable DNS server.",
			ConfigPath:   []string{"server.dns.enabled"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_DNS_ENABLED"},
			DefaultValue: false,
		},
		&cli.StringFlag{
			Name:         "dns-listen",
			Usage:        "The address and port to listen on for DNS queries.",
			ConfigPath:   []string{"server.dns.listen"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_DNS_LISTEN"},
			DefaultValue: ":3053",
		},
		&cli.StringSliceFlag{
			Name:       "dns-records",
			Usage:      "The DNS records to add, can be specified multiple times.",
			ConfigPath: []string{"server.dns.records"},
			EnvVars:    []string{config.CONFIG_ENV_PREFIX + "_DNS_RECORDS"},
		},
		&cli.IntFlag{
			Name:         "dns-default-ttl",
			Usage:        "Default TTL for records if a TTL isn't explicitly set.",
			ConfigPath:   []string{"server.dns.default_ttl"},
			EnvVars:      []string{config.CONFIG_ENV_PREFIX + "_DNS_DEFAULT_TTL"},
			DefaultValue: 300,
		},
	},
	Commands: []*cli.Command{
		ConfigWizardCmd,
	},
	Run: func(ctx context.Context, cmd *cli.Command) error {
		return RunServer(cmd, nil)
	},
}

Functions

func RunServer added in v0.33.0

func RunServer(cmd *cli.Command, quit <-chan struct{}) error

RunServer runs the knot server, blocking until a termination signal is received or the quit channel is closed (used by desktop mode to stop the server from the tray). A nil quit channel is valid and blocks forever.

func ServerFlags added in v0.33.0

func ServerFlags() []cli.Flag

ServerFlags returns the flags accepted by the server command. They are also attached to the root command so bare `knot` (desktop mode) accepts them.

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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