Documentation
¶
Overview ¶
Package app is nib's entrypoint, importable so nib can be embedded in another binary. nib's own main.go is a thin wrapper over Main.
Index ¶
Constants ¶
const ExitCodeApprovalNoInput = 3
ExitCodeApprovalNoInput is the exit code for a CLI session that refused a tool call because stdin was closed and nothing could approve it. See cmd.ErrApprovalNoInput for why that is not a success.
It is deliberately neither 0 nor 1: a script piping a prompt in has to be able to tell "answered" from "refused to act" without reading stdout, and from a crash or a bad flag (2) without guessing. Scripts branch on this number, so it is part of nib's interface and does not change.
Variables ¶
This section is empty.
Functions ¶
func Main ¶
Main runs nib and returns a process exit code. argv is the full argument vector including the program name. It routes through the same code as Run, so the process-wide xlog side effect noted there applies here too.
func Run ¶
Run runs nib and returns an error. It never calls os.Exit.
Every failure comes back as a bare ExitError carrying nothing but an exit code, the cause having been written to Stderr instead: an unparseable flag, an unknown --init shell, an MCP transport failure, the setup abort, the injected-stream refusal and a management subcommand's non-zero code are all indistinguishable to the caller. The code is 1 for every one of those except two: an unparseable flag is 2, and a CLI session that had to refuse a tool call because stdin could not approve it is ExitCodeApprovalNoInput.
Cancelling ctx unwinds whichever mode is running, the TUI included, and comes back as ExitError{1} with the context's error on Stderr. Signals are the caller's: this entrypoint installs no handler, and nothing below it listens for one either.
Run also reconfigures the process-wide xlog logger from the resolved config, which an embedder sharing that logger will observe.
Types ¶
type ExitError ¶
type ExitError struct{ Code int }
ExitError carries a non-zero exit code out of Run.
type Options ¶
type Options struct {
// Args are the arguments after the program name (os.Args[1:]).
Args []string
// ProgramName is the name shown in the messages this package prints itself:
// the --version line, the flag package's usage and parse errors, the setup
// gate's two aborts, and the injected-stream refusal. Empty means "nib".
//
// It also renames the --init shell snippets, which is more than a cosmetic
// substitution: the widget they define invokes this name, so an embedder's
// Ctrl+Space runs the embedder's command rather than a `nib` its users do
// not have. A name of several words ("local-ai chat") stays several words
// in command position, and the widget's function name is derived from it by
// reducing it to an identifier.
//
// It reaches nothing beyond that, so parts of an embedded nib still say
// "nib" whatever this is set to: the management subcommands' usage strings
// ("usage: nib plugin ..." and its skill and mcp equivalents), and the
// "nib: ..." diagnostics that config loading and plugin/skill discovery
// write straight to os.Stderr on every run. Threading the name through
// those is follow-up work.
ProgramName string
// BaseDir overrides the config, plugins, and skills root. Empty means
// nib's default XDG resolution.
BaseDir string
// Stdin, Stdout, Stderr default to the process streams when nil.
//
// CLI mode (--cli) reads and writes exactly these. The TUI, which is the
// DEFAULT mode, does not: it renders on /dev/tty, because the terminal is
// still there even when stdout is a pipe, and serving that case is why it
// opens /dev/tty at all. Only the shell-capture line the TUI prints on exit
// goes to Stdout.
//
// For an embedder that is a rule rather than a caveat: injecting a Stdin or
// a Stdout that is NOT a terminal (a buffer, a pipe, a file) requires --cli,
// or the run is refused with an error saying so, rather than rendering into
// a stream the TUI cannot drive. Injecting the process streams, or any other
// terminal, leaves every mode working.
//
// Only those two are gated (see decideStreamRefusal). A non-terminal Stderr
// is always accepted, because every error this package prints goes through
// o.stderr() rather than through the TUI, so a TUI session with its error
// output captured to a buffer or a log file is a supported combination.
//
// One consequence is worth spelling out, because it inverts the usual
// instinct that passing os.Stdout is the safe, explicit choice. An embedder
// that wants nib's shell-capture idiom, where the user runs
// `out=$(myprog agent)` and the TUI prints the selected command on stdout
// for the shell to capture, must leave Stdout NIL rather than set it to
// os.Stdout. Nil means "not injected": nib falls back to the process stream,
// the TUI runs, and the capture line lands on stdout as it should. Setting
// os.Stdout explicitly injects whatever stdout happens to be, and under
// $(...) that is a pipe, so the run is refused for a stream nib would have
// used anyway.
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
// Defaults seed config fields the config file leaves empty. Every field of
// types.Config is seedable except BaseDir, which is ignored: the root has
// exactly one knob, the BaseDir field above, and it overwrites any seeded
// value. See config.LoadOptions.Defaults for what "empty" means for maps,
// slices and booleans, including that a seeded true beats an explicit
// `false:` in the config file for every bool.
Defaults types.Config
// SkipSetup suppresses the first-run model wizard. Embedders that resolve
// the model themselves set this. It suppresses the whole gate, so an
// explicit --setup in Args becomes a silent no-op rather than an error.
SkipSetup bool
// SkipBareEnv suppresses the bare MODEL / API_KEY / BASE_URL variables, and
// only those three. nib's prefixed variables keep reading the ambient
// environment and still outrank a seed: NIB_TRACE_DIR overrides a seeded
// TraceDir, NIB_YOLO forces ApprovalMode to "auto" over a seeded one, and
// LOG_FORMAT selects the log encoding.
SkipBareEnv bool
}
Options configures a nib invocation. The zero value reproduces standalone nib's behavior exactly, so embedders opt in to each difference.