browser

package module
v0.0.0-...-133c50d Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 32 Imported by: 0

README

browser

Declarative configuration for Chromium-family browsers

Go Nix Flakes Platforms MIT License


browser turns one TOML file into a configured Chromium-family browser. Given an existing browser app or bundle, it can:

  • create a launcher with reproducible flags;
  • install Chrome Web Store, CRX, update-URL, and release ZIP extensions;
  • patch Chromium Preferences, Local State, and Variations;
  • populate extension storage.local and storage.sync; and
  • install Linux desktop entries and icons.

There are no bundled browser defaults, extensions, or hidden preference changes. The browser binary is also yours to install and update.

Quick start

Requires Go 1.26 or Nix with flakes enabled.

go build ./cmd/browser
cp browser.example.toml browser.toml

Edit browser.toml using browser.example.toml as a reference, then run:

./browser configure \
  --config browser.toml \
  --mode macos \
  --root "$HOME/Library/Caches/my-browser" \
  --bin-dir "$HOME/.local/bin"

Use --mode linux on Linux. If the application directory is not set in TOML, pass it with --app-dir.

With Nix:

nix run . -- configure \
  --config browser.toml \
  --mode linux \
  --root "$HOME/.cache/my-browser" \
  --bin-dir "$HOME/.local/bin"

configure installs the declared extensions, applies settings to the configured profile, and writes the launcher. Run it again whenever the configuration changes.

Commands

Command Purpose
configure Install extensions, apply profile settings, and create a launcher
apply-profile-settings Apply browser preferences and extension storage to an existing profile
apply-extension-settings Apply extension storage only
version Print the installed version

Every command has built-in help:

./browser configure --help

Configuration

browser.example.toml is the complete starting point. Only browser.executable_name is universally required; platform paths and metadata depend on how your browser is packaged.

[browser]
name = "Chromium"
executable_name = "chromium"
flags = ["--no-first-run", "--no-default-browser-check"]

[browser.macos]
app_dir = "/Applications/Chromium.app"
launcher_path = "Contents/MacOS/Chromium"

[browser.paths.macos]
profile_dir = "${home}/Library/Application Support/Chromium/Default"

Path values may use ${home}, ${config_home}, and ${data_home}. Relative extension-settings paths resolve from the TOML file. Relative flags-file paths resolve beneath the platform's XDG configuration home.

Launcher flags are applied in this order, with later layers taking precedence: TOML browser.flags, platform wrapper flags, configure --flags, the optional flags file, then arguments passed directly to the launcher.

Extensions

Choose the source that matches the update policy you want:

TOML entry Behavior
[[extensions.chrome_store]] Follow the newest compatible Web Store release
[[extensions.update_url]] Register an external extension update URL
[[extensions.crx]] Install a versioned, SHA-256-pinned CRX
[[extensions.zip]] Follow a GitHub release or install a pinned ZIP

Pinned downloads require a checksum. Set GITHUB_TOKEN when accessing private repositories or when you need higher GitHub API limits.

Browser and extension settings

Browser preferences are declared under [browser.preferences]. Dedicated cookie-policy fields cover defaults, third-party cookies, and site exceptions; generic path/value entries are available for Chromium-specific preferences.

Helium and Brave features have typed, opt-in sections so product preferences do not need to be expressed as raw dotted paths:

[browser.helium.services]
enabled = true
user_consented = true
extension_proxy = true
ublock_assets = true

[browser.helium.toolbar]
show_extensions_button = false

[browser.helium]
crash_reporting = "ask" # disabled | ask | automatic

[browser.brave.tabs]
vertical = true
floating = true
on_right = false
hover_mode = "card" # tooltip | card | card_with_preview

[browser.brave.sidebar]
show = "mouseover" # always | mouseover | never

[browser.brave.shields]
adblock_only_mode = false
custom_filters = "example.com##.sponsor"

When Helium is configured with --set-user-color=R,G,B, the launcher flag is also persisted to the profile's browser and extension theme preferences.

Extension storage is described by ordered JSON files:

[extension_settings]
files = ["settings/base.json", "settings/work.json"]

The format supports top-level values plus set, merge, append, remove, and clear operations for storage.local and storage.sync. Runtime values can be supplied with --input. See schema/extension-settings.schema.json for the complete format.

Later settings files override or extend earlier files. Files passed with repeatable --settings arguments are applied after the files declared in TOML.

Close the browser before changing profile or extension storage. All settings documents are parsed and validated before mutation, and locked extension storage is reported as an error.

Nix modules

The flake exports Home Manager, NixOS, and nix-darwin modules:

inputs.browser.url = "github:4evy/browser";

# Home Manager
imports = [ inputs.browser.homeModules.default ];

Use nixosModules.default or darwinModules.default instead when NixOS or nix-darwin owns the configuration. Then configure it with:

{
  programs.browser = {
    enable = true;

    settings.browser = {
      name = "Chromium";
      executable_name = "chromium";
      paths.linux.profile_dir = "\${config_home}/chromium/Default";
    };

    configurations.brave.browser = {
      name = "Brave";
      executable_name = "brave";
      paths.linux.profile_dir =
        "\${config_home}/BraveSoftware/Brave-Browser/Default";
    };
  };
}

Home Manager writes files to $XDG_CONFIG_HOME/browser; NixOS and nix-darwin write them to /etc/browser. Modules generate configuration and install the CLI only—profile mutation remains an explicit browser command.

Set package = null to generate configuration without installing the CLI. The flake also exports overlays.default and lib.generateConfig.

Development

go test ./...

# Or run the full Nix checks:
nix develop
nix fmt
nix flake check

Released under the MIT License.

Documentation

Index

Constants

View Source
const (
	PreferencesFilename = "Preferences"
	LocalStateFilename  = "Local State"
	VariationsFilename  = "Variations"
)

Variables

This section is empty.

Functions

func ApplyExtensionSettings

func ApplyExtensionSettings(ctx context.Context, options ApplyOptions) error

func Configure

func Configure(ctx context.Context, options ConfigureOptions) error

func EnsureAcceleratorAdded

func EnsureAcceleratorAdded(customAccelerators map[string]any, commandID, accelerator string)

func LinuxDesktopEntry

func LinuxDesktopEntry(text, executable, sourceExec, startupWMClass string) (string, error)

func NestedObject

func NestedObject(root map[string]any, dottedPath string) (map[string]any, error)

func ReadLocalState

func ReadLocalState(profileDir string) (map[string]any, error)

func ReadPreferences

func ReadPreferences(profileDir string) (map[string]any, error)

func ReadVariations

func ReadVariations(profileDir string) (map[string]any, error)

func RunLauncher

func RunLauncher(invocation string, arguments []string) (bool, error)

RunLauncher detects whether invocation names an installed browser launcher. If it does, RunLauncher replaces the current process with the configured browser and returns only when preparing or executing the browser fails.

func SetCookieAllowlist

func SetCookieAllowlist(preferences map[string]any, patterns []string) error

func SetCookiePolicy

func SetCookiePolicy(preferences map[string]any, policy CookiePreferenceConfig) error

SetCookiePolicy updates Chromium's default cookie setting, third-party cookie mode, and per-pattern exceptions. A nil exception list is unmanaged. A non-nil list owns exceptions with that setting, including when the list is empty and therefore removes existing exceptions of that setting.

func SetNestedValue

func SetNestedValue(root map[string]any, dottedPath string, value any) error

func ValidateExtensionSettingsFiles

func ValidateExtensionSettingsFiles(paths []string) error

func WriteLocalState

func WriteLocalState(profileDir string, localState map[string]any) error

func WritePreferences

func WritePreferences(profileDir string, preferences map[string]any) error

func WriteVariations

func WriteVariations(profileDir string, variations map[string]any) error

Types

type ApplyInput

type ApplyInput struct {
	CookieAllowlist []string       `json:"cookie_allowlist"`
	ExtensionValues map[string]any `json:"extension_values"`
}

func DecodeApplyInput

func DecodeApplyInput(reader io.Reader) (ApplyInput, error)

DecodeApplyInput reads exactly one input document and rejects unknown fields.

type ApplyOptions

type ApplyOptions struct {
	ProfileDir         string
	Settings           []string
	SettingsSource     []SettingsSource
	ExtensionIDAliases map[string]string
	Input              ApplyInput
}

type BraveConfig

type BraveConfig struct {
	Tabs    BraveTabsConfig    `toml:"tabs"`
	Sidebar BraveSidebarConfig `toml:"sidebar"`
	Shields BraveShieldsConfig `toml:"shields"`
}

BraveConfig exposes preferences implemented by Brave rather than upstream Chromium. Every field is opt-in; an omitted value leaves the profile alone.

func (BraveConfig) HasLocalStatePreferences

func (config BraveConfig) HasLocalStatePreferences() bool

func (BraveConfig) HasProfilePreferences

func (config BraveConfig) HasProfilePreferences() bool

func (BraveConfig) PatchLocalState

func (config BraveConfig) PatchLocalState(localState map[string]any) error

func (BraveConfig) PatchPreferences

func (config BraveConfig) PatchPreferences(preferences map[string]any) error

type BraveShieldsConfig

type BraveShieldsConfig struct {
	AdBlockOnlyMode *bool   `toml:"adblock_only_mode"`
	CustomFilters   *string `toml:"custom_filters"`
	FacebookEmbeds  *bool   `toml:"facebook_embeds"`
	TwitterEmbeds   *bool   `toml:"twitter_embeds"`
	LinkedInEmbeds  *bool   `toml:"linkedin_embeds"`
}

type BraveSidebarConfig

type BraveSidebarConfig struct {
	Show BraveSidebarShowMode `toml:"show"`
}

type BraveSidebarShowMode

type BraveSidebarShowMode string
const (
	BraveSidebarShowAlways    BraveSidebarShowMode = "always"
	BraveSidebarShowMouseover BraveSidebarShowMode = "mouseover"
	BraveSidebarShowNever     BraveSidebarShowMode = "never"
)

type BraveTabHoverMode

type BraveTabHoverMode string
const (
	BraveTabHoverTooltip         BraveTabHoverMode = "tooltip"
	BraveTabHoverCard            BraveTabHoverMode = "card"
	BraveTabHoverCardWithPreview BraveTabHoverMode = "card_with_preview"
)

type BraveTabMinWidthMode

type BraveTabMinWidthMode string
const (
	BraveTabMinWidthDefault BraveTabMinWidthMode = "default"
	BraveTabMinWidthMinimum BraveTabMinWidthMode = "minimum"
	BraveTabMinWidthMedium  BraveTabMinWidthMode = "medium"
	BraveTabMinWidthLarge   BraveTabMinWidthMode = "large"
	BraveTabMinWidthFull    BraveTabMinWidthMode = "full"
)

type BraveTabsConfig

type BraveTabsConfig struct {
	HoverMode                   BraveTabHoverMode    `toml:"hover_mode"`
	Vertical                    *bool                `toml:"vertical"`
	Collapsed                   *bool                `toml:"collapsed"`
	ExpandedStatePerWindow      *bool                `toml:"expanded_state_per_window"`
	ShowWindowTitle             *bool                `toml:"show_window_title"`
	HideCompletelyWhenCollapsed *bool                `toml:"hide_completely_when_collapsed"`
	Floating                    *bool                `toml:"floating"`
	ShowToggleButton            *bool                `toml:"show_toggle_button"`
	ExpandedWidth               *int                 `toml:"expanded_width"`
	OnRight                     *bool                `toml:"on_right"`
	ShowScrollbar               *bool                `toml:"show_scrollbar"`
	Tree                        *bool                `toml:"tree"`
	SharedPinned                *bool                `toml:"shared_pinned"`
	AlwaysHideCloseButton       *bool                `toml:"always_hide_close_button"`
	MiddleClickClose            *bool                `toml:"middle_click_close"`
	MinWidth                    BraveTabMinWidthMode `toml:"min_width"`
	ScrollableHorizontal        *bool                `toml:"scrollable_horizontal"`
	ShowHorizontalScrollButtons *bool                `toml:"show_horizontal_scroll_buttons"`
	CompactHorizontal           *bool                `toml:"compact_horizontal"`
}

type Browser

type Browser struct {
	Config            BrowserConfig
	Extensions        extensions.Catalog
	ExtensionSettings []string
	PreferencePatches []PreferencePatch
	LocalStatePatches []PreferencePatch
	VariationPatches  []PreferencePatch
}

func New

func New(config Config) (Browser, error)

func (Browser) ApplyBrowserLocalStateSettings

func (browser Browser) ApplyBrowserLocalStateSettings(profileDir string) error

func (Browser) ApplyBrowserPreferenceSettings

func (browser Browser) ApplyBrowserPreferenceSettings(profileDir string) error

func (Browser) ApplyBrowserVariationSettings

func (browser Browser) ApplyBrowserVariationSettings(profileDir string) error

func (Browser) ApplyExtensionSettings

func (browser Browser) ApplyExtensionSettings(ctx context.Context, options ApplyOptions) error

func (Browser) ApplyProfileSettings

func (browser Browser) ApplyProfileSettings(ctx context.Context, options ApplyOptions) error

func (Browser) Install

func (browser Browser) Install(ctx context.Context, options InstallOptions) error

type BrowserConfig

type BrowserConfig struct {
	Name               string                   `toml:"name"`
	LogPrefix          string                   `toml:"log_prefix"`
	ExecutableName     string                   `toml:"executable_name"`
	AliasName          string                   `toml:"alias_name"`
	FlagsFile          string                   `toml:"flags_file"`
	Flags              []string                 `toml:"flags"`
	UserAgent          string                   `toml:"user_agent"`
	Linux              LinuxConfig              `toml:"linux"`
	MacOS              MacOSConfig              `toml:"macos"`
	Paths              map[string]ModePaths     `toml:"paths"`
	Preferences        PreferenceDefaultsConfig `toml:"preferences"`
	ExtensionIDAliases map[string]string        `toml:"extension_id_aliases"`
	Helium             HeliumConfig             `toml:"helium"`
	Brave              BraveConfig              `toml:"brave"`
}

func (BrowserConfig) DefaultProfileDir

func (config BrowserConfig) DefaultProfileDir(mode Mode) string

func (BrowserConfig) ExternalExtensionDirs

func (config BrowserConfig) ExternalExtensionDirs(mode Mode) []string

type Config

type Config struct {
	Browser           BrowserConfig           `toml:"browser"`
	Extensions        extensions.Catalog      `toml:"extensions"`
	ExtensionSettings ExtensionSettingsConfig `toml:"extension_settings"`
}

func LoadConfig

func LoadConfig(path string) (Config, error)

func (Config) Validate

func (config Config) Validate() error

type ConfigureOptions

type ConfigureOptions struct {
	Config             Config
	Mode               Mode
	Root               string
	AppDir             string
	BinDir             string
	Flags              string
	Settings           []string
	Input              ApplyInput
	ApplySettings      bool
	LauncherExecutable string
}

type CookiePreferenceConfig

type CookiePreferenceConfig struct {
	Default     CookieSetting          `toml:"default"`
	ThirdParty  ThirdPartyCookiePolicy `toml:"third_party"`
	Allow       []string               `toml:"allow"`
	Block       []string               `toml:"block"`
	SessionOnly []string               `toml:"session_only"`
}

func (CookiePreferenceConfig) HasPolicy

func (config CookiePreferenceConfig) HasPolicy() bool

type CookieSetting

type CookieSetting string
const (
	CookieSettingAllow       CookieSetting = "allow"
	CookieSettingBlock       CookieSetting = "block"
	CookieSettingSessionOnly CookieSetting = "session_only"
)

type ExtensionSettingsConfig

type ExtensionSettingsConfig struct {
	Files []string `toml:"files"`
}

ExtensionSettingsConfig names JSON documents that configure chrome.storage for installed extensions. Relative paths are resolved from the TOML configuration file that declares them.

type ExtensionStorageArea

type ExtensionStorageArea string
const (
	ExtensionStorageAreaLocal ExtensionStorageArea = "local"
	ExtensionStorageAreaSync  ExtensionStorageArea = "sync"
)

type ExtensionStorageEncoding

type ExtensionStorageEncoding string
const (
	ExtensionStorageEncodingJSON        ExtensionStorageEncoding = "json"
	ExtensionStorageEncodingLZStringURI ExtensionStorageEncoding = "json-lz-string-uri"
)

type ExtensionStorageEntry

type ExtensionStorageEntry struct {
	ID     string         `json:"id"`
	Values map[string]any `json:"values"`
}

type ExtensionStorageInput

type ExtensionStorageInput struct {
	Name      string                        `json:"name"`
	Area      ExtensionStorageArea          `json:"area"`
	ID        string                        `json:"id"`
	Key       string                        `json:"key"`
	Path      string                        `json:"path,omitempty"`
	Encoding  ExtensionStorageEncoding      `json:"encoding,omitempty"`
	Operation ExtensionStorageOperationKind `json:"operation,omitempty"`
}

type ExtensionStorageOperation

type ExtensionStorageOperation struct {
	ID        string                        `json:"id"`
	Area      ExtensionStorageArea          `json:"area"`
	Key       string                        `json:"key,omitempty"`
	Operation ExtensionStorageOperationKind `json:"operation,omitempty"`
	Path      string                        `json:"path,omitempty"`
	Encoding  ExtensionStorageEncoding      `json:"encoding,omitempty"`
	Value     json.RawMessage               `json:"value,omitempty"`
}

type ExtensionStorageOperationKind

type ExtensionStorageOperationKind string
const (
	ExtensionStorageOperationSet    ExtensionStorageOperationKind = "set"
	ExtensionStorageOperationMerge  ExtensionStorageOperationKind = "merge"
	ExtensionStorageOperationAppend ExtensionStorageOperationKind = "append"
	ExtensionStorageOperationRemove ExtensionStorageOperationKind = "remove"
	ExtensionStorageOperationClear  ExtensionStorageOperationKind = "clear"
)

type ExtensionStorageSettings

type ExtensionStorageSettings struct {
	Schema        string                      `json:"$schema,omitempty"`
	SchemaVersion int                         `json:"schema_version,omitempty"`
	Name          string                      `json:"name,omitempty"`
	Description   string                      `json:"description,omitempty"`
	Local         []ExtensionStorageEntry     `json:"local,omitempty"`
	Sync          []ExtensionStorageEntry     `json:"sync,omitempty"`
	LocalAppend   []ExtensionStorageEntry     `json:"local_append,omitempty"`
	SyncAppend    []ExtensionStorageEntry     `json:"sync_append,omitempty"`
	Operations    []ExtensionStorageOperation `json:"operations,omitempty"`
	Inputs        []ExtensionStorageInput     `json:"inputs,omitempty"`
}

ExtensionStorageSettings is the public JSON document accepted by extension_settings.files and --settings. The legacy local/sync fields remain useful for bulk top-level writes, while Operations supports precise mutation of JSON documents stored beneath individual chrome.storage keys.

type HeliumConfig

type HeliumConfig struct {
	CompletedOnboarding *bool                    `toml:"completed_onboarding"`
	Services            HeliumServicesConfig     `toml:"services"`
	Toolbar             HeliumToolbarConfig      `toml:"toolbar"`
	CrashReporting      HeliumCrashReportingMode `toml:"crash_reporting"`
}

HeliumConfig exposes preferences implemented by Helium rather than upstream Chromium. Every field is opt-in; an omitted value leaves the profile alone.

func (HeliumConfig) HasLocalStatePreferences

func (config HeliumConfig) HasLocalStatePreferences() bool

func (HeliumConfig) HasProfilePreferences

func (config HeliumConfig) HasProfilePreferences() bool

func (HeliumConfig) PatchLocalState

func (config HeliumConfig) PatchLocalState(localState map[string]any) error

func (HeliumConfig) PatchPreferences

func (config HeliumConfig) PatchPreferences(preferences map[string]any) error

type HeliumCrashReportingMode

type HeliumCrashReportingMode string
const (
	HeliumCrashReportingDisabled  HeliumCrashReportingMode = "disabled"
	HeliumCrashReportingAsk       HeliumCrashReportingMode = "ask"
	HeliumCrashReportingAutomatic HeliumCrashReportingMode = "automatic"
)

type HeliumServicesConfig

type HeliumServicesConfig struct {
	Enabled         *bool   `toml:"enabled"`
	UserConsented   *bool   `toml:"user_consented"`
	OriginOverride  *string `toml:"origin_override"`
	ExtensionProxy  *bool   `toml:"extension_proxy"`
	Bangs           *bool   `toml:"bangs"`
	SpellcheckFiles *bool   `toml:"spellcheck_files"`
	BrowserUpdates  *bool   `toml:"browser_updates"`
	UBlockAssets    *bool   `toml:"ublock_assets"`
}

type HeliumToolbarConfig

type HeliumToolbarConfig struct {
	ShowBackButton       *bool `toml:"show_back_button"`
	ShowReloadButton     *bool `toml:"show_reload_button"`
	ShowAvatarButton     *bool `toml:"show_avatar_button"`
	ShowExtensionsButton *bool `toml:"show_extensions_button"`
	ShowMenuButton       *bool `toml:"show_menu_button"`
	ShowMediaButton      *bool `toml:"show_media_button"`
}

type InstallOptions

type InstallOptions struct {
	Mode               Mode
	Root               string
	AppDir             string
	BinDir             string
	Flags              []string
	Settings           []string
	SettingsSource     []SettingsSource
	Input              ApplyInput
	ApplySettings      bool
	LauncherExecutable string
	// contains filtered or unexported fields
}

type LinuxConfig

type LinuxConfig struct {
	AppDir       string   `toml:"app_dir"`
	DesktopID    string   `toml:"desktop_id"`
	PortalAppID  string   `toml:"portal_app_id"`
	WrapperFlags []string `toml:"wrapper_flags"`
	LauncherName string   `toml:"launcher_name"`
	DesktopName  string   `toml:"desktop_name"`
	DesktopExec  string   `toml:"desktop_exec"`
	IconName     string   `toml:"icon_name"`
	IconSource   string   `toml:"icon_source"`
}

type MacOSConfig

type MacOSConfig struct {
	AppDir       string `toml:"app_dir"`
	LauncherPath string `toml:"launcher_path"`
}

type Mode

type Mode string
const (
	ModeMacOS Mode = "macos"
	ModeLinux Mode = "linux"
)

type ModePaths

type ModePaths struct {
	ProfileDir            string   `toml:"profile_dir"`
	ExternalExtensionDirs []string `toml:"external_extension_dirs"`
}

type PreferenceAcceleratorConfig

type PreferenceAcceleratorConfig struct {
	Path        string `toml:"path"`
	CommandID   string `toml:"command_id"`
	Accelerator string `toml:"accelerator"`
}

type PreferenceDefaultsConfig

type PreferenceDefaultsConfig struct {
	Values           []PreferenceValueConfig       `toml:"values"`
	LocalStateValues []PreferenceValueConfig       `toml:"local_state_values"`
	VariationValues  []PreferenceValueConfig       `toml:"variation_values"`
	Accelerators     []PreferenceAcceleratorConfig `toml:"accelerators"`
	Cookies          CookiePreferenceConfig        `toml:"cookies"`
}

func (PreferenceDefaultsConfig) HasPreferences

func (config PreferenceDefaultsConfig) HasPreferences() bool

func (PreferenceDefaultsConfig) PatchLocalState

func (config PreferenceDefaultsConfig) PatchLocalState(localState map[string]any) error

func (PreferenceDefaultsConfig) PatchPreferences

func (config PreferenceDefaultsConfig) PatchPreferences(preferences map[string]any) error

func (PreferenceDefaultsConfig) PatchVariations

func (config PreferenceDefaultsConfig) PatchVariations(variations map[string]any) error

type PreferencePatch

type PreferencePatch func(map[string]any) error

type PreferenceValueConfig

type PreferenceValueConfig struct {
	Path  string `toml:"path"`
	Value any    `toml:"value"`
}

type SettingsSource

type SettingsSource struct {
	Name string
	Data []byte
}

type ThirdPartyCookiePolicy

type ThirdPartyCookiePolicy string
const (
	ThirdPartyCookiePolicyOff           ThirdPartyCookiePolicy = "off"
	ThirdPartyCookiePolicyBlock         ThirdPartyCookiePolicy = "block"
	ThirdPartyCookiePolicyIncognitoOnly ThirdPartyCookiePolicy = "incognito_only"
)

Directories

Path Synopsis
cmd
browser command
internal

Jump to

Keyboard shortcuts

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