Documentation
¶
Overview ¶
ckeletin:allow-custom-command
ckeletin:allow-custom-command
This file is not a command — it's a helper for ask.go's --read flag. The ultra-thin-command validator (ADR-001) flags it because of its location (`cmd/`); the whitelist comment opts out of that check. The logic is small and ask-specific (resolving --read rank/id and composing search + body-fetch + render), so keeping it next to ask.go rather than splitting into a new internal/ package is the leaner shape.
ckeletin:allow-custom-command
`episode` is a utility command with no persistent user-facing config keys: its single flag (--output-dir) defaults to a path inside the project's identity vault, and its positional arg is a path provided per-invocation. There are no viper-bound settings worth the ceremony of the ckeletin config registry + generated constants. The marker above documents the deliberate exception to the MustNewCommand pattern used by config-driven commands elsewhere in cmd/.
Format helpers for `vaultmind experiment *` subcommands.
Consolidated here so each experiment_<subcommand>.go can be wire-only (cobra command + run function + small result types) without each one shipping its own ad-hoc text formatter. Output shape evolves across summary/trace/compare together, not piecemeal.
ckeletin:allow-custom-command
This file is not a command — it's a helper that installs a custom help-rendering function on the root command. The ultra-thin-command validator (ADR-001) flags it because of its location (`cmd/`) and the presence of `cobra.Command` references; the whitelist comment above opts out of that check. The agent-first help layout this file implements is co-designed via inter-agent review and the rationale for *not* moving it to internal/help/ is documented inline in installAgentRootHelp's docstring.
ckeletin:allow-custom-command
cmd/zz_catalog.go ckeletin:allow-custom-command
This file is the SINGLE SOURCE OF TRUTH for the command catalog: the cobra group every user-facing command belongs to, its when-to-use trigger phrase, and the composition of that trigger into each command's --help (Long) text.
Why a "zz_" filename: command registration happens in per-file init() functions scattered across cmd/. Go runs a package's init() functions in filename order, so a "zz_"-prefixed file is guaranteed to run LAST — after every command has been added to the tree. That lets decorateCommandCatalog walk a fully-assembled tree. The four groups themselves are registered in root.go's init() (group registration has no subcommand dependency).
The validator (ADR-001) flags this file because it lives in cmd/ and references cobra.Command without being a thin command; the whitelist comment above opts out. It is catalog wiring, not a command.
Index ¶
- Constants
- Variables
- func EnvPrefix() string
- func Execute() error
- func MustAddToRoot(cmd *cobra.Command)
- func MustNewCommand(meta config.CommandMetadata, runE func(*cobra.Command, []string) error) *cobra.Command
- func NewCommand(meta config.CommandMetadata, runE func(*cobra.Command, []string) error) (*cobra.Command, error)
- func RegisterFlagsForPrefixWithOverrides(cmd *cobra.Command, prefix string, overrides map[string]string) error
- type ConfigPathInfo
Constants ¶
const ( // ConfigPathModeXDG searches XDG-style config directory (default). // On macOS, this means ~/.config/<app> unless XDG_CONFIG_HOME is set. ConfigPathModeXDG = "xdg" // ConfigPathModeNative searches the OS-native config directory. // On macOS, this means ~/Library/Application Support/<app>. ConfigPathModeNative = "native" // ConfigPathModeBoth searches both XDG and native directories. ConfigPathModeBoth = "both" )
Variables ¶
var ( Version = "dev" Commit = "" Date = "" )
var RootCmd = &cobra.Command{ Use: "", Short: "A production-ready Go CLI application", Long: "", SilenceErrors: true, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { if err := bindFlags(cmd); err != nil { return fmt.Errorf("failed to bind flags: %w", err) } if f := cmd.Root().PersistentFlags().Lookup("output-format"); f != nil && f.Changed { output.SetOutputMode(f.Value.String()) } output.SetCommandName(cmd.Name()) zerolog.SetGlobalLevel(zerolog.InfoLevel) if err := initConfig(); err != nil { return err } if err := logger.Init(nil); err != nil { return fmt.Errorf("failed to initialize logger: %w", err) } output.SetOutputMode(viper.GetString(config.KeyAppOutputFormat)) if output.IsJSONMode() { zerolog.SetGlobalLevel(zerolog.Disabled) } if configFileStatus != "" { if configFileUsed != "" { log.Debug().Str("config_file", logger.SanitizePath(configFileUsed)).Msg(configFileStatus) } else { log.Debug().Msg(configFileStatus) } } telemetry := viper.GetString(config.KeyExperimentsTelemetry) if telemetry == experiment.TelemetryOff { log.Debug().Msg("Experiments disabled (telemetry: off)") } else if expDB, expErr := openExperimentDB(); expErr != nil { log.Debug().Err(expErr).Msg("Experiment DB unavailable") } else { if telemetry == "" { if firstRun, _ := expDB.IsFirstRun(); firstRun { if isatty.IsTerminal(os.Stdin.Fd()) { telemetry = experiment.PromptTelemetry(os.Stdin, cmd.ErrOrStderr()) viper.Set(config.KeyExperimentsTelemetry, telemetry) if cf := viper.ConfigFileUsed(); cf != "" { if err := persistTelemetryChoice(telemetry, cf); err != nil { log.Debug().Err(err).Msg("Failed to persist telemetry choice to config file") } } if telemetry == experiment.TelemetryOff { log.Debug().Msg("User chose telemetry: off") _ = expDB.Close() return nil } } else { log.Debug().Msg("Non-interactive session, defaulting to anonymous telemetry") } } } if recovered, recErr := expDB.RecoverOrphans(); recErr != nil { log.Debug().Err(recErr).Msg("Failed to recover orphan sessions") } else if recovered > 0 { log.Debug().Int("recovered", recovered).Msg("Recovered orphan experiment sessions") } caller, callerMeta := experiment.DetectCaller() sid, startErr := expDB.StartSessionWithCaller("", caller, callerMeta) if startErr != nil { log.Debug().Err(startErr).Msg("Failed to start experiment session") _ = expDB.Close() } else { outcomeWindow := viper.GetInt(config.KeyExperimentsOutcomeWindowSessions) if outcomeWindow <= 0 { outcomeWindow = 2 } experimentSession = &experiment.Session{DB: expDB, ID: sid, OutcomeWindow: outcomeWindow} cmd.SetContext(experiment.WithSession(cmd.Context(), experimentSession)) } } return nil }, PersistentPostRunE: func(cmd *cobra.Command, args []string) error { if experimentSession != nil { _ = experimentSession.DB.EndSession(experimentSession.ID) _ = experimentSession.DB.Close() experimentSession = nil } return nil }, }
Export RootCmd so that tests in other packages can manipulate it without getters/setters.
Functions ¶
func EnvPrefix ¶
func EnvPrefix() string
EnvPrefix returns a sanitized environment variable prefix based on the binary name
func MustAddToRoot ¶
MustAddToRoot adds a command to RootCmd and sets up configuration inheritance.
This is a convenience wrapper that combines two common operations:
- Adding the command to the root command
- Setting up command configuration to inherit from parent
Usage:
func init() {
MustAddToRoot(myCmd)
}
This should be called in the init() function of your command file.
func MustNewCommand ¶
func MustNewCommand(meta config.CommandMetadata, runE func(*cobra.Command, []string) error) *cobra.Command
MustNewCommand creates a Cobra command and panics on error.
This is a convenience wrapper for NewCommand intended for use in init() functions where there's no way to handle errors gracefully. For testable code or runtime command creation, use NewCommand instead.
Usage in init():
var myCmd = MustNewCommand(config.MyMetadata, runMy)
The runE function signature must be: func(*cobra.Command, []string) error
func NewCommand ¶
func NewCommand(meta config.CommandMetadata, runE func(*cobra.Command, []string) error) (*cobra.Command, error)
NewCommand creates a Cobra command from metadata following ckeletin-go patterns.
This helper enforces the ultra-thin command pattern by:
- Creating the command from metadata (Use, Short, Long)
- Auto-registering flags from the config registry
- Applying custom flag overrides from metadata
Returns an error if flag registration fails, allowing callers to handle errors gracefully.
Usage:
cmd, err := NewCommand(config.MyMetadata, runMy)
if err != nil {
return err
}
For init() functions where you want to panic on error, use MustNewCommand instead.
The runE function signature must be: func(*cobra.Command, []string) error
func RegisterFlagsForPrefixWithOverrides ¶
func RegisterFlagsForPrefixWithOverrides(cmd *cobra.Command, prefix string, overrides map[string]string) error
RegisterFlagsForPrefixWithOverrides registers Cobra flags for all configuration options whose keys start with the provided prefix. It binds each flag to Viper using the option's key. Flag names are derived from the key suffix by converting underscores to hyphens, unless an explicit override is provided in the overrides map. Returns an error if flag binding fails.
Types ¶
type ConfigPathInfo ¶
type ConfigPathInfo struct {
// ConfigName is the base config name without extension (e.g. "config")
// Viper will search for config.yaml, config.yml, config.json, config.toml
ConfigName string
// XDGDir is the XDG-style config directory (e.g. "$XDG_CONFIG_HOME/myapp" or "~/.config/myapp")
XDGDir string
// NativeDir is the OS-native config directory (e.g. macOS "~/Library/Application Support/myapp").
NativeDir string
// Mode controls which user config directory is searched: xdg, native, or both.
Mode string
// SearchPaths lists all viper search paths in priority order.
SearchPaths []string
}
ConfigPaths returns configuration paths for the application.
Config file search order (handled by viper):
- --config flag (explicit override)
- ./config.{yaml,yml,json,toml} (project-local config)
- User config directory based on path mode: - xdg (default): $XDG_CONFIG_HOME/<binaryName> or ~/.config/<binaryName> - native: OS-native config path (macOS: ~/Library/Application Support/<binaryName>) - both: xdg first, then native
Viper automatically detects the file format based on extension.
func ConfigPaths ¶
func ConfigPaths() ConfigPathInfo
Source Files
¶
- activation.go
- apply.go
- arc.go
- arc_candidates.go
- ask.go
- ask_read.go
- completion.go
- config.go
- dataview.go
- dataview_lint.go
- dataview_render.go
- deprecation_helpers.go
- docs.go
- docs_helpers.go
- doctor.go
- doctor_all_helpers.go
- doctor_heal.go
- doctor_heal_wikilinks.go
- episode.go
- experiment.go
- experiment_compare.go
- experiment_format.go
- experiment_report.go
- experiment_summary.go
- experiment_trace.go
- export.go
- flags.go
- frontmatter.go
- frontmatter_fix.go
- frontmatter_fix_core.go
- frontmatter_helpers.go
- frontmatter_merge.go
- frontmatter_normalize.go
- frontmatter_set.go
- frontmatter_unset.go
- frontmatter_validate.go
- git.go
- git_status.go
- help_template.go
- helpers.go
- hooks.go
- hooks_install.go
- hooks_install_helpers.go
- hooks_uninstall.go
- hooks_uninstall_helpers.go
- index.go
- index_calibration.go
- init.go
- init_scaffold.go
- init_wire.go
- links.go
- links_in.go
- links_neighbors.go
- links_out.go
- lint.go
- lint_fix_links.go
- memory.go
- memory_context_pack.go
- memory_links.go
- memory_neighbors.go
- memory_neighbors_helpers.go
- memory_pack.go
- memory_pack_helpers.go
- memory_recall.go
- memory_related.go
- memory_summarize.go
- note.go
- note_create.go
- note_get.go
- note_mget.go
- ping.go
- resolve.go
- root.go
- schema.go
- schema_list_types.go
- search.go
- self.go
- telemetry.go
- vault.go
- vault_discovery.go
- vault_status.go
- version.go
- zz_catalog.go