Documentation
¶
Overview ¶
bashy is a Bash 5.3 compatible shell built on top of interp.
Index ¶
- Variables
- func BashyVersion() string
- func BuildID() string
- func Main()
- func MaybeRunJobCarrierHelper()
- func NewSessionRunner(io SessionIO) (*interp.Runner, error)
- func RunSessionCommand(ctx context.Context, io SessionIO) int
- type BashPPBinary
- type BashPPResolution
- type BashPPSelector
- type BashPPSource
- type SessionIO
Constants ¶
This section is empty.
Variables ¶
var ( AgentOSDispatch = func() {} // AgentOSShutdown runs immediately before the shell exits, on EVERY exit path. // // A shell exits with os.Exit, and os.Exit DOES NOT RUN DEFERRED FUNCTIONS. So a // `defer shutdown()` in main() is dead code in a shell — which is exactly how the // first version of bashy's OTel wiring shipped: it built, five unit tests passed // against an in-memory recorder, and a real collector received ZERO BYTES, because // the batch span processor was never flushed. // // A test that mocks the emitter proves the emitter was CALLED. It does not prove the // data arrived. Only an exit hook does, in a program that exits like this one. AgentOSShutdown = func() {} // posix is passed so AgentOS extensions (e.g. --dry-run) stay inert under // --posix and absent from the pure bash drop-in. AgentOSWireExec func([]interp.RunnerOption, bool, []string, io.Reader, io.Writer, io.Writer) []interp.RunnerOption = func(o []interp.RunnerOption, _ bool, _ []string, in io.Reader, out, err io.Writer) []interp.RunnerOption { return append(o, interp.StdIO(in, out, err)) } // AgentOSPreamble returns shell source defining default functions/aliases // (e.g. `docker() { … bashy podman … }`) registered BEFORE user startup files // so the user can override them. No-op for the pure `bash` drop-in. AgentOSPreamble = func() string { return "" } // AgentOSUsage returns bashy-only usage text appended to `--help`. The pure // bash drop-in leaves it empty so its help stays close to GNU Bash. AgentOSUsage = func() string { return "" } // AgentOSCommandLineNoExec lets the bashy-only front end request the // interpreter's parse-only path without exposing a non-Bash option through // the pure bash binary. It is used to make --dry-run --posix fail safe: // POSIX mode does not install AgentOS execution handlers, so the combination // must validate input without executing it. AgentOSCommandLineNoExec func(bool) bool = func(bool) bool { return false } // AgentOSStrictPosixParse selects the portable POSIX grammar for an // AgentOS validation request. Ordinary bash --posix keeps Bash grammar. AgentOSStrictPosixParse func(bool) bool = func(bool) bool { return false } // AgentOSBashPPDefault identifies the bashy entry point without coupling the // shared CLI package to cmd/bashy. The pure bash binary leaves this false. AgentOSBashPPDefault = false // SuppressedForkBuiltins names the qiangli/sh fork's extra builtins that the // pure `bash` drop-in disables so its command table matches bash 5.3 exactly. // bash 5.3 has NONE of these as builtins (source-verified: no matching .def); // disabling them makes the name resolve to the real external command (or // "not found" where absent, e.g. setsid on macOS), byte-identical to bash: // - nohup, setsid: the fork builtins them for in-process detach over a // closed SSH session; the drop-in defers to /usr/bin/{nohup,setsid}. // - newgrp: the fork builtin is a non-functional stub ("not supported") // that shadows the WORKING external /usr/bin/newgrp — the drop-in defers // to the real one, which actually switches group like bash. // - strmatch: an engine-only builtin bash never had; the drop-in carries // no non-bash command. (The internal `[[ ]]` matcher is a direct Go call, // unaffected by disabling the user-facing builtin.) // - awd: bashy's "alter working directory" agentic builtin; bash never had // it, so the drop-in resolves the name externally ("command not found"). // The `bashy` AgentOS shell clears this in its init() to KEEP them — an // in-process embedded shell needs `nohup foo &` to survive a closed remote // session, which an external nohup over a goroutine job can't do. Users opt // out per command with the bash-native `enable -n <name>`. SuppressedForkBuiltins = []string{"nohup", "setsid", "newgrp", "strmatch", "awd"} )
AgentOSDispatch and AgentOSWireExec are the injection points for the AgentOS surface. The pure `bash` drop-in (cmd/bash) leaves them at their no-op defaults, so its import graph never touches coreutils. The `bashy` system shell (cmd/bashy) sets them to the internal/agentos implementations. This is what keeps the two binaries independent.
var ( VersionProduct = "GNU bash" VersionCompatibility string )
VersionProduct and VersionCompatibility control only the human-facing --version banner. The pure cmd/bash binary keeps the GNU-compatible banner; cmd/bashy overrides these labels so the AgentOS product does not claim to be GNU Bash. BASH_VERSION remains the compatibility version in both binaries.
Functions ¶
func BashyVersion ¶ added in v0.12.0
func BashyVersion() string
BashyVersion returns bashy's own release version ("0.9.1") extracted from the stamped bashVersion suffix ("5.3.0(1)-bashy-v0.9.1"), or "" for an unstamped/dev build. Consumers (the skills host-version probe) treat "" as "omit".
func BuildID ¶ added in v0.17.0
func BuildID() string
BuildID returns the stamped Git build identifier, usually an exact release tag or a short commit SHA with an optional "-dirty" suffix.
func MaybeRunJobCarrierHelper ¶ added in v0.20.0
func MaybeRunJobCarrierHelper()
MaybeRunJobCarrierHelper turns the current process into a job-carrier helper — a kernel-visible stand-in for one background job — when argv is exactly [argv0, "--bashy-job-carrier"]. It never returns in that case.
It must run before flag parsing, startup files, AgentOS dispatch and telemetry: a carrier is pure process identity and must not execute shell or user code. cli.Main calls it first; cmd/bashy additionally calls it before telemetry.Init so a carrier never initializes the OTel plane.
The platform hook relays externally delivered terminating signals through the carrier wait status, including notify-only signals the Go runtime would otherwise consume. Its lifetime is bounded by the parent-owned stdin pipe: it exits on EOF, so it cannot outlive a parent shell that dies without reaping it.
func NewSessionRunner ¶ added in v0.5.0
NewSessionRunner builds a runner for one warm-session request. It mirrors newRunner's `-c` command path faithfully — same coreutils userland wiring (AgentOSWireExec), same bash version vars, PATH default, exported-function import and AgentOS preamble — but takes its stdio/env/dir explicitly instead of reading process globals, so a single process can serve many callers.
Types ¶
type BashPPBinary ¶ added in v0.21.0
type BashPPBinary string
BashPPBinary identifies which of the two compiled entry points (BashPPBinaryBash, cmd/bash's pure Bash 5.3 drop-in, or BashPPBinaryBashy, cmd/bashy's AgentOS shell) is resolving the dialect. It is the "binary default" tier and identifies the pure bash front door whose Sprint 114 POSIX+Bash++ combination is an inert compatibility profile.
const ( BashPPBinaryBash BashPPBinary = "bash" BashPPBinaryBashy BashPPBinary = "bashy" )
type BashPPResolution ¶ added in v0.21.0
type BashPPResolution struct {
Enabled bool
Source BashPPSource
Posix bool
}
BashPPResolution is the resolved dialect selector: whether Bash++ is on, and which precedence tier decided it.
func ResolveBashPP ¶ added in v0.21.0
func ResolveBashPP(sel BashPPSelector) (BashPPResolution, error)
ResolveBashPP resolves the initial Bash++ dialect for one selector, applying the documented precedence (explicit CLI > environment > .bpp extension > binary default). For the pure bash front door, .bpp is only a filename and an affirmative Bash++ selector paired with startup POSIX mode selects the Sprint 114 inertness profile: both extensions and POSIX-mode parser/runtime differences are disabled so its result is byte-identical to the selector-off, POSIX-off invocation. Ordinary bash --posix and explicit --no-bashpp retain the POSIX profile. bashy --posix --bashpp remains a supported combined mode because bashy is not the Classic front door.
func (BashPPResolution) LangVariant ¶ added in v0.21.0
func (r BashPPResolution) LangVariant() syntax.LangVariant
LangVariant returns the concrete construction-time interpreter dialect.
func (BashPPResolution) ParserOptions ¶ added in v0.21.0
func (r BashPPResolution) ParserOptions(base syntax.LangVariant, extra ...syntax.ParserOption) []syntax.ParserOption
ParserOptions composes the selected grammar with the POSIX semantic profile. Keeping both decisions in one API prevents callers from selecting LangBashPP while accidentally dropping syntax.PosixMode(true).
type BashPPSelector ¶ added in v0.21.0
type BashPPSelector struct {
// Binary is which compiled entry point is asking. Required.
Binary BashPPBinary
// Args is an os.Args-shaped slice (Args[0] is the program name, not
// scanned). May be nil.
Args []string
// LookupEnv resolves an environment variable by name, in the shape of
// os.LookupEnv. May be nil, meaning no environment tier.
LookupEnv func(name string) (value string, ok bool)
// Filename is the script path about to be parsed ("" for -c/stdin/
// interactive input). The .bpp convention is only a source label for the
// Bash++-default bashy binary; the bash drop-in requires an explicit
// CLI/environment selector.
Filename string
// Posix is the already-resolved startup POSIX mode (effectiveStartupPosix
// in main.go), not merely the --posix flag's literal presence.
Posix bool
}
BashPPSelector is the input to ResolveBashPP: everything the precedence chain reads to decide the initial grammar for one parse. It takes an argv-shaped slice and an env lookup func, rather than reading os.Args and os.Environ directly, so resolution stays a pure, independently testable function — main.go supplies the real values when B2 wires this in.
type BashPPSource ¶ added in v0.21.0
type BashPPSource string
BashPPSource names which precedence tier decided a BashPPResolution.
const ( BashPPSourceCLI BashPPSource = "cli" // --bashpp / --bash++ / --no-bashpp BashPPSourceEnv BashPPSource = "env" // BASHY_BASHPP=1|0 BashPPSourceExtension BashPPSource = "extension" // .bpp BashPPSourceBinaryDefault BashPPSource = "binary-default" // bash off, bashy on )
func (BashPPSource) Explicit ¶ added in v0.21.0
func (s BashPPSource) Explicit() bool
Explicit reports whether the source is a deliberate user request (a CLI flag or an environment variable) rather than an inferred default (the file extension or the binary's product default).
type SessionIO ¶ added in v0.5.0
type SessionIO struct {
Command string // the -c command string
Dir string // working directory ("" = server cwd)
Env []string // caller environment (replaces os.Environ())
Stdin io.Reader // caller stdin
Stdout io.Writer // caller stdout
Stderr io.Writer // caller stderr
}
SessionIO carries the per-request stdio/env/dir for a command run inside a warm `bashy serve` session. One serve process builds a fresh runner per request from this, so a session-routed `bashy -c "…"` behaves identically to a cold `bashy -c "…"` while skipping the process- and package-init tax.