LibraLibra
LibraLibra
DocsBlogLibra
Getting Started
Architecture
Design
Commands
libra addlibra agentlibra alternateslibra applylibra archivelibra authlibra automationlibra bisectlibra blamelibra branchlibra bundlelibra cachelibra cat-filelibra check-attrlibra check-ignorelibra check-mailmaplibra checkoutlibra cherry-picklibra cleanlibra clonelibra cloudlibra code-controllibra codelibra commit-treelibra commitlibra completionslibra configlibra credentiallibra depslibra describelibra diff-fileslibra diff-indexlibra diff-treelibra difflibra dirtylibra fast-exportlibra fast-importlibra fetchlibra filelibra for-each-reflibra format-patchlibra fscklibra gclibra graphlibra greplibra hash-objectlibra hookslibra hydratelibra index-packlibra initlibra investigatelibra layerlibra lfslibra loglibra logfilelibra loginlibra logoutlibra ls-fileslibra ls-remotelibra ls-treelibra maintenancelibra medialibra merge-baselibra merge-filelibra mergelibra metadatalibra mvlibra noteslibra oplibra openlibra pack-objectslibra packagelibra prunelibra publishlibra pulllibra pushlibra read-treelibra rebaselibra refloglibra remotelibra repacklibra replacelibra rererelibra resetlibra restorelibra rev-listlibra rev-parselibra revertlibra reviewlibra revisionlibra rmlibra sandboxlibra servicelibra shortloglibra show-reflibra showlibra sparse-viewlibra stashlibra statslibra statuslibra switchlibra symbolic-reflibra taglibra update-indexlibra update-reflibra usagelibra verify-packlibra whoamilibra worktreelibra write-tree
API Reference
Policy
Commands

libra config

Command reference for `libra config`

libra config manages repository-local and user-global configuration stored in SQLite-backed config_kv, including vault-backed secrets and key management.

Alias: cfg

Synopsis

libra config <subcommand> [options]
libra config set [--global | --system] [--add] [--encrypt] [--plaintext] [--stdin] <key> [<value>]
libra config get [--global | --system] [--all] [--reveal] [--regexp] [-d <default>] <key>
libra config list [--global | --system] [--name-only] [--show-origin] [--vault] [--ssh-keys] [--gpg-keys]
libra config unset [--global | --system] [--all] <key>
libra config import [--global]
libra config path [--global | --system]
libra config generate-ssh-key --remote <name>
libra config generate-gpg-key [--name <name>] [--email <email>] [--usage <usage>]

Git-compatible flag style is also supported (hidden from help):

libra config [--get | --get-all | --unset | --unset-all | -l | --add | --import | --get-regexp | --show-origin] [--local | --global | --system] [-z | --null] [--type <t> | --bool | --int | --path] [key] [value] [-d <default>]
libra config --remove-section <name>
libra config --rename-section <old-name> <new-name>

Description

libra config reads and writes configuration values across three scopes: local (repository-level, stored in .libra/libra.db), global (user-level, stored in ~/.libra/config.db), and system (machine-wide, stored in /etc/libra/config.db; lowest cascade precedence, plain config only — no vault). Each database uses SQLite with a config_kv table.

Unlike Git's plaintext INI files or jj's TOML files, Libra stores configuration in a transactional database with integrated vault encryption. Sensitive values (API keys, tokens, SSH private keys) are automatically encrypted at rest using AES-256-GCM.

The command supports two invocation styles:

  1. Subcommand style (preferred): libra config set key value, libra config get key
  2. Git-compatible flag style (hidden): libra config --get key, libra config key value

When reading a value with get, Libra cascades through scopes in precedence order: local, then global. The first match wins.

Options

Subcommands

set <key> [<value>]

Set a configuration value. If <value> is omitted and the key is sensitive, Libra prompts for interactive input (hidden echo). In non-interactive contexts (CI/CD), use --stdin to pipe the value.

FlagDescription
--addAdd as an additional value for the key, allowing duplicates (like Git's multi-valued keys such as remote.origin.fetch)
--encryptForce vault encryption even if the key does not match sensitive-key heuristics
--plaintextForce plaintext storage, skipping auto-encryption even for sensitive-looking keys
--stdinRead the value from stdin instead of a positional argument (useful for piping secrets in CI/CD)
# Basic set
libra config set user.name "Jane Doe"

# Set global config
libra config set --global user.email "[email protected]"

# Force encryption
libra config set --encrypt custom.api_token "sk-abc123"

# Set from stdin (CI/CD)
echo "$SECRET" | libra config set --stdin vault.env.GEMINI_API_KEY

# Add multi-value key
libra config set --add remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

# Sensitive key prompts interactively when value omitted
libra config set vault.env.GEMINI_API_KEY

get <key>

Retrieve a configuration value. Cascades from local to global scope, returning the first match.

FlagDescription
--allReturn all values for this key (multi-valued keys)
--revealShow the actual decrypted value for encrypted entries (blocked for internal vault credentials like vault.roottoken_enc)
--regexpTreat <key> as a regex pattern and return all matching entries
-d, --default <value>Return this value if the key is not found (instead of an error)
# Simple get
libra config get user.name

# Get with default fallback
libra config get -d "unknown" user.name

# Get all values for a multi-value key
libra config get --all remote.origin.fetch

# Reveal an encrypted value
libra config get --reveal vault.env.GEMINI_API_KEY

# Regex search
libra config get --regexp "user\\..*"

list

List all configuration entries in the active scope.

FlagDescription
--name-onlyShow only key names, not values
--show-originPrefix each entry with its scope (local or global)
--vaultShow only vault.env.* entries
--ssh-keysShow SSH key entries
--gpg-keysShow GPG key entries
# List all local entries
libra config list

# List with scope labels
libra config list --show-origin

# List only vault environment entries
libra config list --vault

# List only key names
libra config list --name-only

# List SSH keys
libra config list --ssh-keys

unset <key>

Remove a configuration entry.

FlagDescription
--allRemove all values for this key (for multi-valued keys)
# Remove a key
libra config unset user.signingkey

# Remove all values for a multi-valued key
libra config unset --all remote.origin.fetch

import

Import configuration from the user's Git config (.gitconfig). Copies relevant entries into Libra's config database.

# Import from Git global config into Libra global config
libra config import --global

# Import into local config
libra config import

path

Print the filesystem path of the config database for the active scope.

# Show local config path
libra config path
# Output: /path/to/repo/.libra/libra.db

# Show global config path
libra config path --global
# Output: /home/user/.libra/config.db

edit

Not supported. Libra uses SQLite storage, which cannot be safely round-tripped through a text editor. See Design Rationale for details.

generate-ssh-key --remote <name>

Generate an SSH key pair for the named remote. The private key is stored encrypted in the vault (vault.ssh.<remote>.privkey); the public key is stored at vault.ssh.<remote>.pubkey.

libra config generate-ssh-key --remote origin
libra config get vault.ssh.origin.pubkey

generate-gpg-key

Generate a GPG key pair for commit signing or encryption.

FlagDescription
--name <name>User name for the key (defaults to user.name config)
--email <email>User email for the key (defaults to user.email config)
--usage <usage>Key usage: signing (default) or encrypt
# Generate signing key
libra config generate-gpg-key

# Generate encryption key with explicit identity
libra config generate-gpg-key --name "Jane Doe" --email "[email protected]" --usage encrypt

# Retrieve the public key
libra config get vault.gpg.pubkey

Scope Flags

These flags are global (apply to any subcommand):

FlagDescription
--localUse repository config (.libra/libra.db). This is the default for writes.
--globalUse global user config (~/.libra/config.db).
--systemUse system-wide config (/etc/libra/config.db, overridable via LIBRA_CONFIG_SYSTEM_DB). Lowest cascade precedence; writing it usually requires elevated privileges. Vault-encrypted secrets are not supported in this scope (see Design Rationale).

Hidden Git-Compatible Flags

These flags provide backward compatibility with git config invocation patterns. They are hidden from --help. Most translate to the equivalent subcommand; --remove-section / --rename-section are flag-only section operations with no subcommand form.

FlagEquivalent Subcommand / Behavior
--getget <key>
--get-allget --all <key>
--unsetunset <key>
--unset-allunset --all <key>
-l, --listlist
--addset --add <key> <value>
--importimport
--get-regexpget --regexp <key>
--show-originlist --show-origin
--type=<bool|int|path>, --bool, --int, --pathCanonicalize a value when reading (--get/--get-all/--get-regexp) and when setting: bool variants → true/false; int with optional k/m/g (1024-based) multiplier; path expands a leading ~/~/. On a set the value is validated/canonicalized before storage (matching git config --type: yes → true, 1k → 1024), and an invalid value errors without storing. A non-get/non-set mode is rejected (exit 129).
--remove-section <name>Delete the keys in section <name> in one transaction, using Git's section/subsection identity (so --remove-section branch removes branch.<key> but not the branch.feature.* subsection). Missing section → exit 128.
--rename-section <old> <new>Move section <old>'s keys to <new>, preserving each value and its encryption flag. Missing source → exit 128; identical names → exit 2; an already-existing destination section is refused → exit 128.

Other Flags

FlagDescription
-d, --default <value>Default value when key is not found (Git-compat positional mode)
-z, --nullNUL-terminate output records (git config -z): value\0 for --get/--get-all; key\nvalue\0 for --get-regexp/--list; key\0 with --name-only; origin\0 prefix with --show-origin. --json takes precedence. Applies to standard config output only; combining it with --ssh-keys/--gpg-keys/--vault is rejected (exit 129).
--jsonEmit structured JSON output
--quietSuppress human-readable output

Common Commands

libra config set user.name "Jane Doe"
libra config get user.name
libra config list
libra config list --show-origin
libra config unset user.signingkey
libra config import
libra config path

Human Output

get prints the value on a single line:

Jane Doe

list prints key-value pairs:

user.name=Jane Doe
[email protected]
core.editor=vim

With --show-origin:

local   user.name=Jane Doe
global  [email protected]

With --name-only:

user.name
user.email
core.editor

set prints nothing on success (exit code 0).

path prints the database path:

/home/user/repo/.libra/libra.db

Structured Output (JSON examples)

get:

{
  "command": "config",
  "data": {
    "key": "user.name",
    "value": "Jane Doe",
    "origin": "local"
  }
}

list:

{
  "command": "config",
  "data": {
    "entries": [
      { "key": "user.name", "value": "Jane Doe", "origin": "local" },
      { "key": "user.email", "value": "[email protected]", "origin": "global", "encrypted": false }
    ]
  }
}

Secrets And Vault Entries

Sensitive keys are stored encrypted when they match Libra's sensitive-key rules, including:

  • vault.env.*
  • *.privkey
  • API keys, tokens, passwords, and similar secret-looking keys

Examples:

libra config set vault.env.GEMINI_API_KEY
echo "$SECRET" | libra config set --stdin vault.env.GEMINI_API_KEY
libra config set --encrypt custom.api_token "secret"
libra config get vault.env.GEMINI_API_KEY
libra config get --reveal vault.env.GEMINI_API_KEY
libra config list --vault

--reveal is blocked for internal vault credentials such as vault.roottoken_enc and vault.ssh.<remote>.privkey.

Key Management

SSH keys are generated per remote and stored in config:

libra config generate-ssh-key --remote origin
libra config get vault.ssh.origin.pubkey
libra config list --ssh-keys

GPG public keys are exposed through config, while private signing material stays inside vault.db:

libra config generate-gpg-key
libra config generate-gpg-key --usage encrypt
libra config get vault.gpg.pubkey
libra config list --gpg-keys

Supported --usage values are signing and encrypt.

Scope

  • Default scope is local (.libra/libra.db)
  • --global uses ~/.libra/config.db
  • --system uses /etc/libra/config.db (override with LIBRA_CONFIG_SYSTEM_DB); lowest cascade precedence, writes usually need elevated privileges, and vault-encrypted secrets are rejected in this scope (see Design Rationale)

Resolution order for runtime config-backed environment variables is:

  1. CLI arguments
  2. Local config (vault.env.<NAME>)
  3. Global config (vault.env.<NAME>)
  4. Process environment variables

If no Vault entry or process environment variable supplies a required API key, Libra reports the missing key and asks you to set vault.env.<NAME> or export <NAME>.

Design Rationale (Why different from Git/jj)

Why SQLite instead of text files?

Git uses INI-format text files; jj uses TOML. Libra uses SQLite because:

  1. Transactional writes. SQLite provides ACID guarantees. A crash mid-write cannot corrupt the configuration, unlike a partially-written text file. This is critical when multiple AI agents may write config concurrently.
  2. Structured queries. Multi-valued keys, prefix searches, and regex matching are SQL queries rather than text parsing. This eliminates an entire class of escaping and parsing bugs.
  3. Integrated encryption. Vault-encrypted values are stored as encrypted blobs alongside plaintext values in the same table. A text file format would need a separate encryption layer or inline encoding scheme.

Why vault encryption?

Git stores configurations in plaintext INI files, which is inherently insecure for storing API keys, access tokens, and SSH/GPG private keys. Libra integrates Vault-backed encrypted storage natively. Sensitive keys (like vault.env.*, *.privkey, or keys containing substrings like secret/token) are automatically encrypted at rest using AES-256-GCM in both local and global scopes. This eliminates the "redacted in CLI but plaintext on disk" false sense of security, allowing developers to safely store environment overrides directly within the configuration.

Why does --system reject vault-encrypted secrets?

--system reads and writes plain system-wide config at /etc/libra/config.db (override with LIBRA_CONFIG_SYSTEM_DB), at the lowest cascade precedence — like Git's /etc/gitconfig. Writing it usually requires elevated privileges, and a present-but-unreadable system DB is skipped during cascade reads rather than crashing other users' commands.

What it deliberately does not support is the vault: storing encrypted secrets (vault.* keys or --encrypt values) in the system scope is rejected with a usage error. In a multi-user OS environment, a system-level unseal key under root-owned /etc/libra would either be unreadable to regular users (breaking decryption) or world-readable (defeating the encryption). System-wide secrets should be handled at the OS/environment level; Libra keeps the vault to --global (user-level) and --local (repository) scopes.

Why no config edit?

Libra uses a SQLite database (config_kv table) instead of plaintext files. Exporting database rows to a text editor and parsing the unified diff back into SQL UPDATE/DELETE statements is dangerous. Specifically, for multi-value keys (e.g., remote.origin.fetch), the plaintext representation lacks row-level primary keys. Reordered, partially modified, or deleted lines would prevent Libra from accurately mapping text changes to database rows, inevitably leading to data loss or corruption. To guarantee data consistency, you must use the robust set, --add, unset, and list commands.

Why built-in SSH/GPG key management?

Instead of scattering SSH private keys as plaintext files on the filesystem, Libra stores them encrypted inside the config vault (vault.ssh.<remote>.privkey). When an SSH transport is invoked, the key is dynamically decrypted to a temporary file (chmod 600), passed to the SSH client, and deleted immediately afterward. GPG private keys are managed exclusively by the vault's internal PKI engine and are never exported to the filesystem.

Why subcommand style as the primary interface?

Git uses git config key value (implicit set) and git config key (implicit get), which is ambiguous: git config foo could be a get or an incomplete set. Libra follows jj's lead by requiring explicit subcommands (set, get, list, unset). The Git-compatible flag style (--get, -l, etc.) is preserved as hidden aliases for migration, but the subcommand style is the documented interface because it is unambiguous, discoverable via --help, and easier for AI agents to generate correctly.

Why --default instead of exit-code differentiation?

Git exits with code 1 when a key is not found, which is indistinguishable from other errors in scripts. Libra's --default flag provides an explicit fallback value, allowing scripts and agents to handle missing keys without error-code parsing.

Parameter Comparison: Libra vs Git vs jj

FeatureGitjjLibra
Implicit setgit config key valNo (requires set)libra config set key val plus compatible libra config key val
Subcommand styleNoYes (set/get/list/edit/path)Yes (set/get/list/unset/import/path)
Get valuegit config keyjj config get keylibra config get key
Listgit config -ljj config listlibra config list
Edit in editorgit config -ejj config editNot supported (SQLite storage)
Regex searchgit config --get-regexpNolibra config get --regexp
Show origingit config --show-originNolibra config list --show-origin
Type coercion--type=bool|int|pathNo (TOML types)--type=bool|int|path + --bool/--int/--path (canonicalize on both read and set)
Default fallback--default valueNo--default value
Null-delimited-zNo-z / --null (value\0 for get/get-all; key\nvalue\0 for --get-regexp/--list; key\0 with --name-only)
Rename/remove sectionYesNo--remove-section / --rename-section (Git section/subsection semantics; rename refuses an existing destination)
JSON outputNoNo--json
Secret redactionNoNoAuto-detect
Import from GitN/AN/Alibra config import
Vault encryptionNoNoAES-256-GCM (local/global only; rejected in system scope)
Env var vaultNoNovault.env.*
SSH key per remoteNoNogenerate-ssh-key --remote
GPG key generationNoNogenerate-gpg-key
Env var resolutionNo fallbackNo fallbackCLI -> env -> repo -> global
Config file pathN/Ajj config pathlibra config path
Conditional configincludeIf[[when]] blocksNot supported
Worktree scope--worktree--workspaceNot supported
Arbitrary file--file <path>NoNot supported
Storage formatINI text filesTOML text filesSQLite + vault
Scopessystem/global/local/worktreeuser/repo/workspacesystem/global/local (system: plain config only, no vault; no worktree scope)
Name-only listing--name-onlyNo--name-only
Multi-value add--addNoset --add
Stdin inputNoNoset --stdin
Force encryptNoNoset --encrypt
Force plaintextNoNoset --plaintext

Error Handling

CodeConditionHint
LBR-REPO-001Not inside a libra repository (for local scope)Initialize with libra init or use --global
LBR-CLI-002Vault-encrypted secret (vault.*/--encrypt) in --system scopeUse --global or --local for vault secrets
LBR-CLI-003Key not found and no --default providedCheck key name with libra config list
LBR-CLI-002edit subcommand used (not supported)Use set, get, unset, list subcommands
LBR-IO-001Failed to read config databaseCheck file permissions on .libra/libra.db
LBR-IO-002Failed to write config databaseCheck file permissions and disk space

Compatibility Notes

  • libra vault has been removed. Use libra config generate-ssh-key, libra config generate-gpg-key, and libra config get vault.* instead.
  • libra config edit is not supported (see Design Rationale above).
  • Old repositories may still contain legacy vault.gpg_pubkey entries; new writes use vault.gpg.pubkey.

libra completions

Command reference for `libra completions`

libra credential

Command reference for `libra credential`

On this page

SynopsisDescriptionOptionsSubcommandsset <key> [<value>]get <key>listunset <key>importpatheditgenerate-ssh-key --remote <name>generate-gpg-keyScope FlagsHidden Git-Compatible FlagsOther FlagsCommon CommandsHuman OutputStructured Output (JSON examples)Secrets And Vault EntriesKey ManagementScopeDesign Rationale (Why different from Git/jj)Why SQLite instead of text files?Why vault encryption?Why does --system reject vault-encrypted secrets?Why no config edit?Why built-in SSH/GPG key management?Why subcommand style as the primary interface?Why --default instead of exit-code differentiation?Parameter Comparison: Libra vs Git vs jjError HandlingCompatibility Notes