Skip to main content

Configuration Reference

Hister is configured via a YAML file. It selects a primary config path using this precedence:

  1. The path supplied with --config.
  2. The path in HISTER_CONFIG, when --config is not supplied.
  3. ./config.yml in the current working directory.

If the selected primary path does not exist, Hister searches the platform paths below and uses the first config file it finds.

Default Config Locations

Linux (respects $XDG_CONFIG_HOME):

  • $XDG_CONFIG_HOME/hister/config.yml if $XDG_CONFIG_HOME is set, otherwise ~/.config/hister/config.yml
  • ~/.histerrc (legacy, deprecated)

macOS (respects $XDG_CONFIG_HOME):

  • $XDG_CONFIG_HOME/hister/config.yml if $XDG_CONFIG_HOME is set, otherwise ~/Library/Preferences/hister/config.yml
  • ~/Library/Application Support/hister/config.yml (backwards compatible)
  • ~/.histerrc (legacy, deprecated)
  • ~/.config/hister/config.yml (legacy)

Windows (respects environment variables):

  • %LOCALAPPDATA%\hister\config.yml (recommended)
  • $XDG_CONFIG_HOME\hister\config.yml (if $XDG_CONFIG_HOME is set)
  • %APPDATA%\hister\config.yml (fallback)
  • ~\.histerrc (legacy, deprecated)
  • ~\.config\hister\config.yml (legacy)

If you have a legacy ~/.histerrc file and Hister finds it, you’ll see a deprecation warning suggesting you move it to the recommended location.

Creating a Config File

Use hister config path to locate the selected main config, hister config show to inspect effective YAML with credentials redacted, and hister config validate to check configuration without creating runtime files. hister doctor also checks connectivity, authentication, index compatibility, and extractor dependencies. See Terminal Client for examples, output formats, and exit statuses.

Generate a config file with default values:

hister config create ~/.config/hister/config.yml

Omit the filename to print YAML to standard output. Existing files are never overwritten. Config creation works even when the current configuration is missing or invalid, and does not initialize runtime data. The old hister create-config command remains a deprecated alias and prints its migration notice to standard error.

Or use your platform’s recommended location:

# Linux
hister config create ~/.config/hister/config.yml

# macOS
hister config create ~/Library/Preferences/hister/config.yml

# Windows
hister config create %LOCALAPPDATA%histerconfig.yml

You can also specify a custom config location using the --config flag:

hister listen --config /path/to/my/config.yml

Important: Restart the Hister server after modifying the configuration file.

Environment Variables

You can override configuration values using environment variables. The naming convention is:

HISTER__<SECTION>__<KEY>=value

For example:

  • HISTER__APP__LOG_LEVEL=debug overrides app.log_level
  • HISTER__APP__LOG_FORMAT=json overrides app.log_format
  • HISTER__APP__LOG_FILE=/var/log/hister.log overrides app.log_file
  • HISTER__SERVER__ADDRESS=0.0.0.0:8080 overrides server.address

Three special purpose variables are also supported:

VariableDescription
HISTER_CONFIGSelect a config file when --config is not supplied
HISTER_PORTOverride the TCP port while keeping the host from server.address. Ignored for Unix sockets.
HISTER_DATA_DIROverride app.directory

Full Configuration

Use the configuration generated by your installed Hister version instead of copying a static example. Print the complete configuration with all current default values:

hister config create

To create the configuration file directly, pass its destination path:

hister config create /path/to/config.yml

Each option below has one or both scope tags. The server tag marks settings used by the Hister server, its index, or the web interface it serves. The client tag marks settings used by command line operations or the terminal interface on the machine where they run. If your client and server use separate configuration files, add a setting to each tagged side where you need its behavior.

app Section

directory
serverclient

Directory where Hister stores its data, including the index, rules, and secret key.

Type string
Default platform default
title
server

Main title shown on the web UI home page.

Type string
Default Hister
subtitle
server

Secondary title shown below the main title on the web UI home page. Set it to an empty string to hide it.

Type string
Default Your own search engine
color_scheme
server

Default web UI color scheme. Supported values are automatic, dark, and light. Visitors can override this default from the appearance menu.

Type string
Default automatic
search_url
server

Fallback web search URL. Use {query} as the placeholder for the search term.

Type string
Default https://google.com/search?q={query}
access_token
serverclient

Optional access token for securing the API. See the Access Token section below.

Type string
Default (none)
user_handling
serverclient

Enables multiple user mode. See the User Handling documentation for details.

Type bool
Default false
public
serverclient

Allows unauthenticated users to search public documents, use API docs, MCP search, previews, and file serving. Requires access_token or user_handling.

Type bool
Default false
log_level
serverclient

Log verbosity. Supported values are error, warning, info, debug, and trace. The err and warn aliases are also accepted.

Type string
Default info
log_format
serverclient

Log output format. Text emits colored human readable lines. JSON emits one object per entry for log aggregators.

Type string
Default text
log_file
serverclient

Path to a log file. Hister creates or appends to this file instead of writing logs to standard error.

Type string
Default (none)
debug_sql
server

Enables verbose SQL query logging.

Type bool
Default false
open_results_on_new_tab
server

Opens search results in a new browser tab instead of the current tab.

Type bool
Default false
redirect_on_no_results
server

Redirects to the configured search_url when a query returns no results. Disable it to remain within Hister.

Type bool
Default true
display_extractor_config
server

Includes extractor option definitions in the extractor API response so clients can display configuration details.

Type bool
Default false
disable_previews
server

Disables the preview panel and prevents HTML storage. See the Disable Previews section below.

Type bool
Default false
profiler
server

Serves the Go runtime profiling endpoints under /debug/pprof, behind the same authentication as the rest of the API.

Type bool
Default false

server Section

address
server

Host and port to listen on, or unix:/absolute/path for a Unix socket. Use [::]:4433 or 0.0.0.0:4433 to listen on all interfaces.

Type string
Default 127.0.0.1:4433
base_url
serverclient

Public URL of the Hister instance. Required when listening on all interfaces or a Unix socket. It must match how you access Hister.

Type string
Default derived from address
database
server

SQLite filename relative to app.directory or a PostgreSQL DSN. See Database Backends below.

Type string
Default db.sqlite3
max_batch_body_size
server

Maximum request body size in MiB accepted by the batch API. Import clients use this value to keep submitted batches within the server limit.

Type int
Default 40
metrics
server

Exposes Prometheus metrics at /metrics under the configured base URL. Uses token authentication when configured and requires an administrator in multiple user mode. See Monitoring for setup and metric definitions.

Type bool
Default false
proxy_auth_header
server

Authenticates users by a header set by a trusted authentication proxy and automatically enables user handling. Unsafe without an authentication proxy and protection against direct access. See Reverse Proxy Authentication below.

Type string
Default (empty, disabled)
oauth
server

Optional map of OAuth or OIDC provider configurations. See OAuth below.

Type map
Default (none)
oauth_only
server

Disables password login. OAuth and token based API access remain accepted. In multiple user mode, a token must belong to a user.

Type bool
Default false

For server.metrics, see Monitoring for authentication, Prometheus scrape configuration, and metric definitions.

For Unix socket permissions and reverse proxy examples, see Unix sockets.

Database Backends

Hister supports SQLite (default) and PostgreSQL.

The server.database value determines which backend is used:

  • If the value contains = it is treated as a PostgreSQL DSN.
  • Otherwise it is treated as an SQLite filename relative to app.directory.

SQLite (default)

server:
  database: 'db.sqlite3'

PostgreSQL

server:
  database: 'host=localhost user=hister password=hister dbname=hister port=5432 sslmode=disable TimeZone=Europe/Budapest'

Hister uses the standard PostgreSQL DSN key=value format. Adjust host, user, password, dbname, port, sslmode, and TimeZone to match your setup.

Hister can augment keyword search with vector similarity search. When enabled, each indexed document gets a metadata vector containing its title, URL, specific extractor type when available, language, author, description, and topic metadata. Document text is split into overlapping structural chunks with compact title and language context, and each chunk is converted to a floating point vector by an external embedding model. The vectors are stored alongside the main index. At search time the query is also embedded and the closest chunks are retrieved, then merged with keyword results and reranked.

Semantic search is opt-in and disabled by default. It requires an OpenAI-compatible embeddings endpoint such as Ollama, a local llama.cpp server, or the OpenAI API itself.

Connection and Model

enable
server

Enables semantic search. All other semantic search settings are ignored when this is disabled.

Type bool
Default false
embedding_endpoint
server

URL of the OpenAI compatible embeddings endpoint.

Type string
Default http://localhost:11434/v1/embeddings
embedding_model
server

Model name passed in each embedding request. It must match a model served by the endpoint.

Type string
Default qwen3-embedding:8b
api_key
server

Optional API key sent as an Authorization bearer token. Hosted providers commonly require it.

Type string
Default ""
headers
server

Optional HTTP headers added to every embedding request for proxies or custom authentication.

Type map[string]string
Default {}
dimensions
server

Requested vector dimensionality. The selected embedding model and endpoint must support this output size. Hister limits PostgreSQL vector storage to 2000 dimensions.

Type int
Default 2000

Chunking and Input

max_context_length
server

Hard context ceiling for each text chunk. Hister reserves five percent as tokenizer headroom, giving the default an approximate budget of 486 tokens. Endpoint rejections trigger another retry with smaller chunks.

Type int
Default 512
chunk_overlap
server

Approximate token allowance shared between consecutive chunks while preserving structural boundaries.

Type int
Default 64
query_prefix
server

Text prepended to every search query. Many embedding models use distinct query and document prefixes for better recall.

Type string
Default "query: "
document_prefix
server

Text prepended to every document chunk. Set it according to the convention expected by the embedding model.

Type string
Default ""

Retrieval

similarity_threshold
server

Minimum cosine similarity required for a semantic chunk to be included in the results.

Type float
Default 0.1
result_limit
server

Maximum number of semantic hits retrieved for each query.

Type int
Default 50
semantic_weight
server

Weight applied to semantic scores when merging them with keyword scores. Zero uses keyword results only, while one uses semantic results only.

Type float
Default 0.4

Processing

embedding_timeout
server

Maximum seconds allowed for one embedding request. Values below one use the default of 300 seconds.

Type int
Default 300
max_embedding_batch_size
server

Maximum chunks sent in one request. Smaller batches keep local endpoints responsive and let long documents make incremental progress. Values below one use the default of eight.

Type int
Default 8
max_embedding_concurrency
server

Maximum embedding workers and simultaneous indexing requests to the endpoint. Query requests have a separate limit. Values below one use the default of two.

Type int
Default 2
max_query_embedding_concurrency
server

Maximum simultaneous query embedding requests, independent of indexing. Values below one use the default of one. Total endpoint concurrency can reach the sum of both limits. Separate slots bypass the local indexing queue but do not reserve capacity or priority on the embedding server.

Type int
Default 1
query_embedding_timeout
server

Maximum seconds allowed for query slot acquisition, the embedding request, and retries combined. On timeout, the search returns its keyword results. This does not bound keyword retrieval or vector lookup. Increase it for slow hardware or model startup. Values below one use the default of two seconds; an earlier caller deadline or embedding_timeout still applies.

Type int
Default 2

Vector Storage Backends

The vector store backend is chosen automatically based on server.database:

  • SQLite (default) stores vectors in a separate vectors.sqlite3 file in the same directory as the main database, using the sqlite-vec extension. No extra setup required.
  • PostgreSQL stores vectors in the same database as the main data using the pgvector extension. Hister uses an HNSW index with the vector type, which supports at most 2000 dimensions. Make sure pgvector is installed and enabled (CREATE EXTENSION vector;) before starting Hister.

Use HISTER__SEMANTIC_SEARCH__QUERY_EMBEDDING_TIMEOUT and HISTER__SEMANTIC_SEARCH__MAX_QUERY_EMBEDDING_CONCURRENCY to override the query deadline and concurrency through environment variables. Changing these settings does not require reindexing.

Set semantic_search.dimensions to the output size supported by your embedding endpoint. If the endpoint returns a different size, Hister rejects the embeddings. After changing dimensions with SQLite, restart Hister and run hister reindex to rebuild the vector table and regenerate embeddings. Existing vectors are preserved until reindexing begins, and startup logs report when the stored dimensions differ from the configuration.

Example

semantic_search:
  enable: true
  embedding_endpoint: 'http://localhost:11434/v1/embeddings'
  embedding_model: 'nomic-embed-text'
  embedding_timeout: 300
  dimensions: 768
  max_context_length: 512
  chunk_overlap: 50
  max_embedding_batch_size: 8
  query_prefix: 'search_query: '
  document_prefix: 'search_document: '
  similarity_threshold: 0.5
  result_limit: 10
  semantic_weight: 0.4
  max_embedding_concurrency: 2
  max_query_embedding_concurrency: 1
  query_embedding_timeout: 2
  # api_key: 'sk-...'            # required for hosted providers
  # headers: {}                  # extra HTTP headers for proxies or custom auth

The example above uses nomic-embed-text via Ollama, which produces 768-dimensional vectors and fits well in a 512-token context window. The query_prefix and document_prefix values shown are the ones recommended by the Nomic model. Other models use different conventions: "query: " / "passage: " for E5 and BGE families (this is also the built-in default for query_prefix), "Represent this sentence for searching relevant passages: " for GTE. Check your model’s documentation for the expected prefix strings. Set both to "" for models that do not use prefixes (such as OpenAI text-embedding-3-*).

TUI Settings

TUI settings are configured in a separate tui.yaml file located in the same directory as your main config file. This file is automatically created with default values when you first run hister search.

Theme Settings

dark_theme
client

Theme used in dark mode. Available themes include Catppuccin, Dracula, Gruvbox, Nord, Rose Pine, and Tokyo Night.

Type string
Default tokyonight
light_theme
client

Theme used in light mode.

Type string
Default catppuccin-latte
color_scheme
client

Appearance mode. Terminal inherits your terminal background, foreground, and ANSI palette. Use auto to choose the configured dark or light Hister theme, or select dark or light explicitly.

Type string
Default terminal
themes_dir
client

Optional directory containing custom theme YAML files.

Type string
Default (built in themes)

Built-in themes: catppuccin-frappe, catppuccin-latte, catppuccin-macchiato, catppuccin-mocha, dracula, gruvbox, gruvbox-light, material-lighter, nord, nord-light, one-light, rose-pine, rose-pine-dawn, solarized-light, tokyonight, and tomorrow.

indexer Section

detect_languages
serverclient

Enables automatic language detection. Changing this setting requires reindexing.

Type bool
Default true
keep_stopwords
server

Preserves stop words while retaining language analysis. Changing this setting requires reindexing.

Type bool
Default false
directories
serverclient

List of local directories to index. See Local Directory Indexing below.

Type Directory[]
Default (none)
max_file_size_mb
serverclient

Maximum file size in megabytes to index. Larger files are skipped.

Type int
Default 1

Directory Entry

Each entry in directories is an object with the following keys:

path
serverclient

Directory path to index. Paths beginning with ~/ are expanded to the home directory.

Type string
Default ""
Required
label
serverclient

Label applied automatically to every file indexed from this directory.

Type string
Default ""
filetypes
serverclient

Only indexes files with these extensions, without the dot. For example: ["txt", "md"].

Type string[]
Default (none)
patterns
serverclient

Only indexes filenames matching at least one glob pattern. For example: ["doc_*", "README*"].

Type string[]
Default (none)
excludes
serverclient

Skips filenames matching any listed glob pattern. For example: ["*secret*", "*.tmp"].

Type string[]
Default (none)
include_hidden
serverclient

Includes hidden files, hidden directories, and common dependency or cache directories. Explicit excludes still apply.

Type bool
Default false
delete_on_remove
server

Automatically removes a file from the index when it is deleted or renamed.

Type bool
Default false
user
server

Username that owns files in this directory. Leave it empty for global access.

Type string
Default ""

When multiple filters are specified, they are applied in order: excludes first, then filetypes, then patterns. A file must pass all specified filters to be indexed. When a filter is omitted, it is not applied (all files pass).

Local Directory Indexing

The indexer.directories option lets you index local files so they appear alongside your browser history in search results. You do not need to run hister import file for configured directories that the server can access. After changing this configuration, restart the Hister server. It scans the directories automatically at startup, then a file watcher monitors them so new and modified files are indexed without another restart.

indexer:
  directories:
    - path: '~/notes'
      filetypes: ['txt', 'md']
      patterns: ['doc_*']
      excludes: ['*secret*']
    - path: '~/Documents/wiki'
      label: 'wiki'
    - path: '/path/to/project'
      label: 'project'
      filetypes: ['go', 'py', 'js']

Set label on a directory to apply the same searchable label to every file indexed from it. Changing a nonempty configured label updates existing files during the next startup scan, even when their contents have not changed. Leaving it empty preserves labels assigned manually.

User-scoped directories

When user_handling is enabled, you can scope indexed files to specific users using the user field. Files in a user-scoped directory are only visible to that user in search results. Global directories (no user set) are visible to all users.

indexer:
  directories:
    - path: '/nextcloud/notes/alice'
      user: 'alice'
      filetypes: ['txt', 'md']
    - path: '/nextcloud/notes/bob'
      user: 'bob'
      filetypes: ['txt', 'md']
    - path: '/shared/docs'
      # no user = global, visible to all
      filetypes: ['pdf', 'docx']

Visibility rules:

  • A user sees files from directories where user == username plus global directories (user empty or unset) plus their own web documents
  • Admins have the same visibility as regular users (no special access to other users’ files)
  • Unauthenticated users see global directories only

Files are indexed recursively, with the following rules:

  • Hidden files and directories (starting with .) are skipped unless include_hidden: true
  • Well-known dependency/cache directories (node_modules, bower_components, jspm_packages, __pycache__, __pypackages__) are skipped unless include_hidden: true
  • Binary files are skipped
  • Files larger than indexer.max_file_size_mb (default: 1 MB) are skipped
  • Files matching sensitive_content_patterns are skipped with a warning that includes the path but no matched content

hister list-files lists files matching the configured directory watch rules. It does not check file contents or report indexing status, so it also lists files rejected by sensitive content, size, or format checks. Rejected files remain watched and are checked again when they change.

Changes to indexed directories are picked up automatically by the file watcher, no server restart is needed. On server start, only files that have been modified since they were last indexed are re-processed. File results appear with the domain local and are served through the Hister web interface directly.

When a configured directory is available to the command line client but not to the server, run hister import file with no path arguments. It applies these directory rules locally, extracts matching content, and creates remote file snapshots through the normal add API. The original bytes are not sent. Add --watch to keep importing new and changed snapshots until interrupted. Watch mode skips exports, archives, and saved HTML with source URL metadata. Remote snapshots are never removed automatically, even with delete_on_remove: true. See Importing Documents for details.

For directories watched by the server, delete_on_remove: true makes deleting or renaming a file on the filesystem remove it from the index automatically. This is optional and disabled by default. It does not apply to remote snapshots imported by the client.

No reindex is required when adding or removing files. Files are detected and indexed automatically. After making directory filters more restrictive, run hister cleanup to remove indexed local documents that no longer match the configuration. Cleanup compares indexed paths with the configuration and does not scan or read the filesystem.

Disable Previews

By default, Hister stores the full HTML content of every indexed page on disk and makes it available in a split-pane preview panel in the search and history UI. Setting disable_previews: true turns this off completely:

  • HTML content is never written to disk during indexing or re-indexing. Only the extracted plain text, title, URL, domain, language, and favicon are kept.
  • Running hister reindex with this option enabled will delete all previously stored HTML files, reclaiming disk space.
  • The preview panel, the per-result view button, and the Preview toggle are hidden in the web UI.

This is useful when disk space is limited or when you prefer not to retain full page snapshots.

app:
  disable_previews: true

Note: Favicons are unaffected by this setting and are always stored.

Access Token

The app.access_token setting provides a simple authentication mechanism to secure your Hister instance. When configured, clients must include the token in API requests using the X-Access-Token header or the Authorization: Bearer TOKEN header. This is particularly useful when exposing Hister to the network or internet, preventing unauthorized access to your browsing history and search index.

To use the access token, set it in your configuration file:

app:
  access_token: 'your-secret-token-here'

The web UI prompts for the access token and exchanges it for an opaque browser session. It does not retain the access token in the cookie or in browser storage. The access token has to be added to the browser extension separately when the extension uses token authentication.

Public Mode

Public mode lets anonymous visitors search the shared index while write access remains authenticated. Enable it with app.public: true or by starting the server with hister listen --public. A public instance must also configure either app.access_token or app.user_handling, otherwise Hister refuses to start.

app:
  public: true
  access_token: 'your-secret-token-here'

server:
  base_url: https://hister.example.com

With user handling, anonymous visitors can only see documents stored under user ID 0. User-owned documents remain visible only to the matching authenticated user.

app:
  public: true
  user_handling: true

Public mode exposes search, suggestions, document reads, previews, file serving, API documentation, and MCP search. It does not allow anonymous users to add, edit, label, delete, change rules, reindex, clean up, access web history, or access profile APIs. Authenticated callers can access web history normally.

Only index content that is meant to be public. Local files, previews, and MCP search can expose indexed document content to anonymous visitors.

For command-line usage with curl or similar tools, include the header in your requests:

curl -H "X-Access-Token: your-secret-token-here" http://localhost:4433/api/config

Security note: API clients transmit the access token in plain text with each request, and the web UI transmits it during login. When exposing Hister over the network, always use HTTPS through a reverse proxy to encrypt credentials and sessions in transit. The token provides basic access control but does not replace proper authentication systems for multiple user scenarios.

Reverse Proxy Authentication

Security warning: Do not enable server.proxy_auth_header without a trusted authentication proxy in front of Hister. Hister trusts the configured header as proof of identity and does not verify that the sender is your proxy. Anyone who can supply that header can impersonate an existing user, including an administrator, or create a new account. HTTPS or a reverse proxy that only forwards traffic does not make this safe.

Before enabling this feature, configure your proxy to authenticate requests, discard any client supplied value of the configured header, and set it from the verified user’s identity. Prevent untrusted clients from reaching Hister directly and bypassing the proxy. Use a loopback listener when the proxy runs on the same host, a Unix socket with restricted permissions, or network rules that restrict backend access to the trusted proxy. Do not expose Hister’s backend port publicly, including through container port publishing.

Once these protections are in place, set the header name in your Hister configuration. This example assumes the authentication proxy runs on the same host and sets Remote-User:

server:
  address: 127.0.0.1:4433
  base_url: https://hister.example.com
  proxy_auth_header: 'Remote-User'

The equivalent environment variable is HISTER__SERVER__PROXY_AUTH_HEADER=Remote-User. Use the header name configured in your proxy, such as Remote-User or X-Forwarded-User. Leaving the setting empty disables proxy authentication.

When enabled:

  • Hister automatically enables app.user_handling.
  • The header value, with surrounding whitespace removed, identifies the Hister username. An existing account keeps its documents, rules, token, and permissions, including administrator privileges. Use unique identities controlled by the authentication service; users must not be able to choose another Hister user’s name.
  • A username without an existing account is automatically created on its first request. New accounts have no administrator privileges and no password, so password login is unavailable unless an administrator assigns one.
  • A successfully authenticated proxy identity takes precedence over session cookies and API tokens. Missing or empty headers fall back to normal session and personal access token authentication. Enabling this option does not disable existing password or OAuth login.

CLI, browser extension, and MCP clients can still use a personal access token through X-Access-Token or Authorization: Bearer TOKEN when the proxy header is absent. They must also satisfy your proxy’s access policy. Do not expose the backend to bypass that policy. In multiple user mode, a token must belong to a Hister user; a standalone app.access_token does not grant access.

Hister’s Logout action only clears its own session. It does not sign you out of the authentication proxy, so subsequent requests carrying the identity header remain authenticated. Sign out through your authentication proxy to end that access.

See User Handling for account management and document ownership, and Server Setup for listener and reverse proxy configuration.

OAuth

When user handling is enabled, Hister supports delegating authentication to external OAuth 2.0 / OpenID Connect providers. Users can then sign in with their existing accounts instead of a Hister-local password.

The server.oauth key is a map where each key is a provider name and the value is its configuration. Three providers are built in:

ProviderDescription
githubGitHub accounts via the GitHub OAuth app
googleGoogle accounts via Google Identity
oidcAny OpenID Connect provider (Keycloak, Authentik, Dex, etc.)

Each entry supports the following fields:

client_id
server

OAuth application client ID issued by the provider.

Type string
Required
client_secret
server

OAuth application client secret issued by the provider.

Type string
Required
configuration_url
server

OIDC discovery URL. For OIDC, either set this or configure auth_url, token_url, and userinfo_url directly.

Type string
Conditional
auth_url
server

Overrides the provider authorization endpoint. Required for OIDC when configuration_url is not set. Optional for GitHub and Google.

Type string
Conditional
token_url
server

Overrides the provider token endpoint. Required for OIDC when configuration_url is not set. Optional for GitHub and Google.

Type string
Conditional
userinfo_url
server

Overrides the OIDC user information endpoint. Required when configuration_url is not set or its discovery response does not provide this endpoint.

Type string
Conditional
scopes
server

Additional OAuth scopes to request. Provider defaults are always included.

Type []string
Optional
identity_claim
server

OIDC only. UserInfo claim used to match a Hister account, such as sub. Empty uses email for compatibility. See OIDC Account Identity before changing this for existing accounts.

Type string
Default email
Optional
disable_pkce
server

Disables S256 PKCE for this provider. Use only for older providers that reject PKCE parameters.

Type bool
Default false
Optional

GitHub Example

Register an OAuth app at github.com/settings/developers. Set the Authorization callback URL to https://your-hister-instance/api/oauth/callback?provider=github.

server:
  oauth:
    github:
      client_id: 'your-github-client-id'
      client_secret: 'your-github-client-secret'

Google Example

Create OAuth credentials in the Google Cloud Console. Add https://your-hister-instance/api/oauth/callback?provider=google as an authorised redirect URI.

server:
  oauth:
    google:
      client_id: 'your-google-client-id'
      client_secret: 'your-google-client-secret'

Generic OIDC Example

server:
  oauth:
    oidc:
      client_id: 'hister'
      client_secret: 'your-client-secret'
      configuration_url: 'https://accounts.example.com/.well-known/openid-configuration'

If your provider does not publish a discovery document, set auth_url, token_url, and userinfo_url directly and omit configuration_url:

server:
  oauth:
    oidc:
      client_id: 'hister'
      client_secret: 'your-client-secret'
      auth_url: 'https://accounts.example.com/oauth/authorize'
      token_url: 'https://accounts.example.com/oauth/token'
      userinfo_url: 'https://accounts.example.com/oauth/userinfo'

OIDC Account Identity

Set identity_claim: 'sub' to identify an OIDC account by its subject, so changing the user’s email address does not create a new Hister account. The OIDC specification defines sub as stable and unique within its issuer. Keep the same issuer when using existing account links.

server:
  oauth:
    oidc:
      client_id: 'hister'
      client_secret: 'your-client-secret'
      configuration_url: 'https://accounts.example.com/.well-known/openid-configuration'
      identity_claim: 'sub'

The equivalent environment variable is HISTER__SERVER__OAUTH__OIDC__IDENTITY_CLAIM=sub. This works with discovery or manually configured endpoints. The option selects an exact, case sensitive field in the UserInfo response. Custom claim names, including URI names, are supported; dots do not select nested fields. Choose a unique, immutable identifier controlled by the provider. Fields users can edit, such as preferred_username, are unsuitable for account matching.

The selected claim must be a nonempty JSON string containing more than whitespace. If it is missing or invalid, login fails without falling back to email. An email address is optional when another claim identifies the account. New usernames use preferred_username, then email, then the OAuth identity if neither is available. Existing usernames are preserved on subsequent logins.

Omitting identity_claim, leaving it empty, or setting it to email preserves existing oidc-<email> account links. Other claims use oidc:<escaped claim name>:<claim value>, for example oidc:sub:abc123. The claim name uses URL query escaping. This separates identities from different claims and from legacy email identities.

Before switching an existing deployment, back up the database and explicitly relink each affected user’s o_auth_id to the new identity using a verified mapping from the provider. Hister does not automatically link accounts by matching email addresses or usernames. Without relinking, a successful login with the new claim creates a separate account, and the old account retains its documents and history. Changing the issuer also requires a verified mapping because subjects are unique only within an issuer.

PKCE and Compatibility

Hister uses PKCE with the S256 challenge method for GitHub, Google, and OIDC logins by default. Each login generates a fresh private verifier stored in the server side session. The authorization request includes its SHA256 challenge, and the token exchange sends the original verifier. This supports providers such as Kanidm with PKCE enforcement enabled, including when OIDC discovery does not advertise PKCE support.

Existing client IDs, client secrets, scopes, callback URLs, and linked accounts continue to work. Client secrets are still required. No database migration or reindexing is needed, and existing authenticated sessions remain valid.

For an older provider that rejects PKCE parameters, explicitly set disable_pkce: true on that provider:

server:
  oauth:
    oidc:
      client_id: 'hister'
      client_secret: 'your-client-secret'
      configuration_url: 'https://accounts.example.com/.well-known/openid-configuration'
      disable_pkce: true

The equivalent environment variable is HISTER__SERVER__OAUTH__OIDC__DISABLE_PKCE=true. Disabling PKCE removes the protection it provides against authorization code interception. Hister does not automatically retry without PKCE after a provider error.

Logins started before upgrading must be restarted because their sessions lack the verifier and provider binding. A callback consumes its matching login state before exchanging the code, so failed or denied logins must also be restarted. GitHub token exchanges now use a form POST to keep credentials and the verifier out of the URL; custom GitHub token endpoints or proxies must accept POST.

How It Works

  1. The login page shows a Sign in with <Provider> button for each configured provider.
  2. Clicking the button redirects the user to the provider’s authorization page.
  3. After the user grants access the provider redirects back to /api/oauth/callback?provider=<name>.
  4. Hister verifies the state token and provider, exchanges the authorization code with the PKCE verifier for a token, and fetches the user’s identity from the provider.
  5. If no local account is linked to that identity, one is created automatically. GitHub uses the login name, Google uses the account name with the full email address as a fallback, and OIDC uses preferred_username, then the full email address, then the OAuth identity as the username.
  6. The user is logged in and redirected to the home page.

Note: OAuth login requires app.user_handling: true. The buttons only appear on the login page when user handling is active and at least one provider is configured.

OAuth-Only Mode

Setting server.oauth_only: true prevents users from authenticating with a username/password. Only OAuth logins are accepted through the web interface.

server:
  oauth_only: true
  oauth:
    github:
      client_id: 'your-github-client-id'
      client_secret: 'your-github-client-secret'

Personal access tokens continue to work regardless of this setting, so API clients, the CLI, and the browser extension can authenticate without a browser login. In multiple user mode, app.access_token is a client default and must contain a user’s personal token to authenticate.

The login page hides the username/password form when oauth_only is active, showing only the OAuth provider buttons.

Note: Use oauth_only with app.user_handling: true and at least one configured OAuth provider. Enabling it without a provider leaves users with no browser login path.

Language Detection

The indexer.detect_languages option (default: true) controls automatic language detection for indexed pages. When enabled, Hister uses language detection libraries to identify the language of each page’s content, creating separate language-specific indexes that improve search accuracy through language-aware tokenization and stemming.

The indexer.keep_stopwords option defaults to false. When enabled together with language detection, Hister retains stop words while continuing to apply the other language analyzer operations, including normalization and stemming. This is useful when quoted phrases must include common words such as for and your.

Performance considerations: Language detection increases both CPU usage and memory consumption. Each document requires additional processing to analyze text and determine its language, and separate indexes are maintained for each detected language. If you’re experiencing memory pressure or slow indexing performance, especially with large numbers of documents, consider disabling this feature.

Important: Changing either analyzer setting requires a full reindex to take effect. After changing detect_languages or keep_stopwords, run:

hister reindex

The reindex operation will rebuild all indexes according to the new settings. Hister stores an analyzer configuration fingerprint and warns at startup when the configured settings differ from those used by the current index. With language detection disabled, all documents are indexed using a single default analyzer, reducing memory overhead and simplifying the indexing process at the cost of potentially less accurate search results.

hotkeys.web Section

Defines keyboard shortcuts for the web interface. Each entry maps a key combination to an action.

Key format: [modifier+]key where modifier is ctrl, alt, or meta. Key can be a letter, digit, or special key (enter, tab, arrowup, arrowdown, etc.).

ActionDescription
focus_search_inputMove focus to the search input box
open_resultOpen the selected (or first) result
open_result_in_new_tabOpen the selected result in a new tab
select_next_resultMove selection to the next result
select_previous_resultMove selection to the previous result
open_query_in_search_engineOpen the current query in the configured fallback search engine
view_result_popupOpen the offline preview popup for the selected result
delete_resultDelete the selected result
autocompleteAccept the autocomplete suggestion
show_hotkeysShow the keyboard shortcuts help overlay

TUI Configuration

TUI-specific settings are stored in a separate tui.yaml file in the same directory as your main config. This file is automatically created with defaults the first time you run hister search.

Default location: ~/.config/hister/tui.yaml (or alongside your config file)

tui.yaml Example

dark_theme: 'tokyonight'
light_theme: 'catppuccin-latte'
color_scheme: 'terminal'

hotkeys:
  ctrl+c: 'quit'
  f1: 'toggle_help'
  tab: 'toggle_focus'
  esc: 'toggle_focus'
  up: 'scroll_up'
  k: 'scroll_up'
  down: 'scroll_down'
  j: 'scroll_down'
  enter: 'open_result'
  y: 'copy_result'
  v: 'toggle_preview'
  l: 'edit_label'
  ctrl+d: 'delete_result'
  ctrl+t: 'toggle_theme'
  ctrl+s: 'toggle_settings'
  ctrl+o: 'toggle_sort'
  ctrl+e: 'toggle_semantic'
  alt+1: 'tab_search'
  alt+2: 'tab_history'
  alt+3: 'tab_rules'
  alt+4: 'tab_add'

The default terminal mode does not paint a terminal-wide foreground or background. Normal text inherits your terminal colors, while semantic accents use its configurable ANSI palette. Set color_scheme to auto, dark, or light to opt into Hister’s full built-in themes. The Settings overlay (ctrl+s) exposes this as Appearance — Terminal (pass-through); press Enter to cycle modes, or use ctrl+t for the full theme picker.

TUI Hotkeys

TUI keyboard shortcuts are configured in tui.yaml under the hotkeys section. See the tui.yaml example above.

ActionDescription
quitExit the TUI
toggle_helpShow/hide the keybindings help overlay
toggle_focusChange focus or return to the previous workspace
scroll_upMove selection up
scroll_downMove selection down
open_resultOpen, edit, or submit the focused item
copy_resultCopy the selected URL
toggle_previewShow/hide selected result details
edit_labelEdit the selected document label
delete_resultDelete the selected entry from the index
toggle_themeOpen the interactive theme picker overlay
toggle_settingsOpen appearance and keybinding settings
toggle_sortToggle domain-based sorting for search results
toggle_semanticToggle semantic search when enabled
tab_searchSwitch to the Search tab
tab_historySwitch to the History tab (view recent searches)
tab_rulesSwitch to the Rules tab (manage allow/skip/priority/versioning rules and aliases)
tab_addSwitch to the Add tab (manually add URLs and multiline text)

crawler Section

The crawler section configures the web crawler used by hister index, hister index --recursive, browser imports, and service imports that need to download bookmark content. These commands share the same backend and request settings. Every recursive crawl runs as a persistent job so it can be interrupted and resumed without losing progress. See Website Crawler for usage details.

backend
client

Scraping backend. Supported values are http, chromedp, and bidi.

Type string
Default http
backend_options
client

Options for the selected backend. See Crawler Backend Options below.

Type map
Default (none)
proxy
client

HTTP or SOCKS5 proxy URL used by every crawler backend.

Type string
Default (none)
timeout
client

Request timeout in seconds.

Type int
Default 5
delay
client

Seconds to wait between requests to avoid overloading target servers.

Type int
Default 0
user_agent
client

Custom User Agent header sent with every request.

Type string
Default (none)
headers
client

Extra HTTP headers sent with every request.

Type map[string]string
Default (none)
cookies
client

Cookies sent with every request. See Crawler Cookies below.

Type Cookie[]
Default (none)
no_robots
client

Disables robots.txt compliance during crawling.

Type bool
Default false

Set proxy to an http:// or socks5:// URL. The HTTP backend uses it as its transport proxy, Chromedp passes it to the browser process, and BiDi requests it when creating the browser session. robots.txt requests use the same proxy. For example:

crawler:
  proxy: 'socks5://127.0.0.1:1080'

Proxy URLs with embedded credentials are rejected because browser backends cannot apply them consistently. You can also set the proxy with HISTER__CRAWLER__PROXY or the --proxy flag.

For BiDi, a configured proxy requires the remote browser to accept session.new with the proxy capability. Initialization fails if the endpoint already owns a session or rejects that capability, so Hister never continues while silently ignoring the proxy.

Crawler Backend Options

The backend_options map passes configuration to the selected backend. Each backend validates its own options and rejects unknown keys.

http backend: no backend specific options supported.

chromedp backend:

Launches Chrome or Chromium on the machine running hister index. Install the browser there and use exec_path if it is not found automatically. This backend launches its own browser process; Hister does not currently expose an option to connect it to a remote CDP socket.

exec_path
client

Path to the Chrome or Chromium binary.

Type string
Default (none)
capture_delay
client

Seconds to wait after page load before capturing HTML for pages that rely on JavaScript rendering.

Type float
Default 0
crawler:
  backend: 'chromedp'
  backend_options:
    exec_path: '/usr/bin/chromium'
    capture_delay: 1.5
  timeout: 15

bidi backend (WebDriver BiDi):

Connects to an already running browser that exposes a WebDriver BiDi WebSocket endpoint. Hister opens the supplied WebSocket and sends session.new; it does not launch a browser or create a session through a WebDriver HTTP server. Firefox supports this direct connection at /session.

Chrome and Chromium’s --remote-debugging-port exposes the Chrome DevTools Protocol (CDP). That socket cannot be used as a BiDi endpoint. Use Hister’s chromedp backend for a local Chrome or Chromium installation.

See Firefox with BiDi for browser startup and indexing commands, or browser backends with Docker when the server is containerized.

socket
client

Full WebSocket URL. When set, host and port are ignored.

Type string
Default (none)
host
client

Hostname or IP address of the browser WebDriver BiDi endpoint.

Type string
Default 127.0.0.1
port
client

Port of the browser WebDriver BiDi endpoint.

Type string
Default 9222
capture_delay
client

Seconds to wait after page load before capturing HTML for pages that rely on JavaScript rendering.

Type float
Default 0

Apply these settings to the configuration used by the indexing command:

crawler:
  backend: 'bidi'
  backend_options:
    host: '127.0.0.1'
    port: '9222'
    capture_delay: 1.5 # wait 1.5s after load for JS to render
  timeout: 15

The host and port options above produce ws://127.0.0.1:9222/session. Alternatively, specify the full socket URL, including /session. When socket is set, it overrides host and port:

crawler:
  backend: 'bidi'
  backend_options:
    socket: 'ws://127.0.0.1:9222/session'

The bidi backend subscribes to network.responseCompleted for the tab it navigates, so pages served with a 4xx or 5xx status are reported as fetch failures instead of being indexed as error pages. Redirects are followed and judged by the status of the final response. Statuses of subresources such as images or favicons are ignored. When the browser does not report the subscription, the status stays unknown and the page is indexed as before.

Firefox only allows a single WebDriver session per browser instance. If another client (an IDE integration, a test runner, Selenium, …) already holds the session, Hister cannot create one and every command fails with invalid session id. Start a dedicated browser instance with its own profile and port for crawling.

Crawler Cookies

Each entry in cookies is an object with the following keys:

name
client

Cookie name.

Type string
Required
value
client

Cookie value.

Type string
Required
domain
client

Domain to which the cookie applies, such as example.com.

Type string
Required
path
client

Cookie path.

Type string
Default /
Optional

Full Crawler Example

crawler:
  backend: 'http'
  proxy: 'http://127.0.0.1:8080'
  timeout: 10
  delay: 2
  user_agent: 'Hister'
  headers:
    Accept-Language: 'en-US,en;q=0.9'
  cookies:
    - name: 'session'
      value: 'abc123'
      domain: 'example.com'
      path: '/'

sensitive_content_patterns Section

A map of named Go regular expression patterns. Hister rejects a web page or local file when its HTML or extracted text matches any pattern. The content is not redacted or indexed. Indexing commands that support --allow-sensitive can explicitly bypass this check.

sensitive_content_patterns:
  my_pattern: 'regex here'

Default patterns cover common secrets: AWS keys, GitHub tokens, SSH/PGP private keys.