Back to Openviking

ovcli Configuration

docs/en/configuration/02-client.md

0.4.1818.1 KB
Original Source

ovcli Configuration

ovcli.conf is the client configuration file for the ov CLI. It stores the server connection, authentication identity, and command defaults.

Agent plugins for Codex, Claude Code, OpenCode, and other clients also read their own OPENVIKING_* environment variables for Recall, Capture, diagnostics, and other behavior. Those variables are not part of ovcli.conf; configure them in the corresponding Agent Integration documentation.

Use ov config to create and maintain configurations. Use ov config show to inspect the active configuration with secrets redacted.

Default path:

text
~/.openviking/ovcli.conf

To select another file:

bash
export OPENVIKING_CLI_CONFIG_FILE=/path/to/ovcli.conf

Complete Example

json
{
  "url": "https://openviking.example.com",
  "api_key": "<user-or-admin-key>",
  "root_api_key": "<root-key>",
  "account": "acme",
  "user": "alice",
  "actor_peer_id": "agent:research-assistant",
  "timeout": 60,
  "output": "table",
  "echo_command": true,
  "show_progress": false,
  "verbose": false,
  "profile": false,
  "upload": {
    "ignore_dirs": "node_modules,.cache,dist",
    "include": "*.md,*.pdf",
    "exclude": "*.tmp,*.log"
  },
  "extra_headers": {
    "X-Tenant": "acme"
  },
  "gateway_token": "<gateway-token>"
}

Omit fields you do not need. A local server in dev mode usually needs only url.

Connection and Authentication

json
{
  "url": "https://openviking.example.com",
  "api_key": "<user-or-admin-key>",
  "root_api_key": "<root-key>",
  "account": "acme",
  "user": "alice",
  "actor_peer_id": "agent:research-assistant",
  "extra_headers": {
    "X-Tenant": "acme"
  },
  "gateway_token": "<gateway-token>"
}
FieldType / ValuesDefaultPurpose
urlHTTP(S) URLhttp://127.0.0.1:1933OpenViking server endpoint
api_keystring / nullnullUser/admin key for normal data operations
root_api_keystring / nullnullRoot key for ov --sudo administrative operations
accountstring / nullnullAccount identity for trusted or root-key-only configurations
userstring / nullnullUser identity for trusted or root-key-only configurations
actor_peer_idstring / nullnullDefault Actor Peer identifier
agent_idstring / nullnullCompatibility field; use actor_peer_id for new configs and do not set both
extra_headersobject / nullnullAdditional headers sent with every request; extra_header is a compatibility alias
gateway_tokenstring / nullnullX-Gateway-Token used when retrying a gateway challenge

Choosing API Keys

ConfigurationNormal Commandsov --sudo
api_key onlyUser/admin keyunavailable
root_api_key plus account and userRoot key with explicit identityRoot key
Both keysapi_keyroot_api_key
No keysLocal server with authentication disabled onlyunavailable

server.root_api_key in ov.conf is accepted by the server. When the CLI manages that server, root_api_key in ovcli.conf must match it.

Command Behavior

json
{
  "timeout": 120,
  "echo_command": true,
  "show_progress": true,
  "verbose": false,
  "profile": false
}
FieldType / ValuesDefaultPurpose
timeoutnumber, seconds, > 060HTTP request timeout
echo_commandbooleantrueShow effective request parameters for commands such as find, search, and ls
show_progressbooleanfalseShow upload progress by default
verbosebooleanfalseShow upload diagnostics by default
profilebooleanfalseRequest performance profiles; also requires server.profile_enabled
output"table" / "json""table"Compatibility field; use -o table or -o json to select current command output

Command-line options such as --profile, --progress, --no-progress, and --verbose override the configuration for the current command.

Upload Filters

json
{
  "upload": {
    "ignore_dirs": "node_modules,.cache,dist",
    "include": "*.md,*.pdf",
    "exclude": "*.tmp,*.log"
  }
}
FieldType / FormatDefaultPurpose
upload.ignore_dirscomma-separated string / nullnullDirectory names to ignore
upload.includecomma-separated globs / nullnullUpload only matching files
upload.excludecomma-separated globs / nullnullExclude matching files

Local directory uploads also honor .gitignore. Command-line --include and --exclude rules are merged with the configuration.

Workspace Configuration

A repository can carry its own plugin settings, so the memory behavior of a project travels with the checkout instead of living in each contributor's home directory. Two files sit under the workspace root, and a third layer is kept per machine:

text
<repo-root>/.openviking/config.json         # committed, shared by the team
<repo-root>/.openviking/config.local.json   # private, not committed
~/.openviking/workspaces/<slot>.json        # per-machine registry, one file per workspace

The workspace root is the nearest ancestor directory holding a .git, or one holding .openviking/config.json (or config.local.json) — whichever the walk upward reaches first; $HOME and the filesystem root are never workspace roots. A directory that is neither is not a workspace at all: no configuration layer, no registry entry, and no peer of its own. The registry slot name combines the root's directory name with a hash of its full path, so two clones of one repository on one machine never share an entry. These layers are read by the Claude Code and Codex plugins, not by ov commands.

Precedence

Highest first:

LayerScope
OPENVIKING_* environment variablesCurrent process
~/.openviking/workspaces/<slot>.jsonThis machine, this workspace
<repo-root>/.openviking/config.local.jsonThis checkout, private
<repo-root>/.openviking/config.jsonThis repository, committed
ovcli.conf plugin.<harness>This machine, one harness
ovcli.conf pluginThis machine, every harness
ov.conf harness sectionCompatibility layer for older deployments
Built-in defaults

A scalar from a higher layer replaces the lower one. Lists are unioned across layers; a leading "!reset" element drops everything the lower layers contributed, so ["!reset", "*/scratch/*"] is the whole list.

No command writes the registry file. Create it by hand at the path ov-memory-doctor prints, with version: 1 and the same schema as the workspace files.

Schema

version: 1 is required. A file declaring another version is skipped with a warning rather than guessed at.

json
{
  "version": 1,
  "peer": { "source": "git" },
  "recall": { "peer_scope": "actor", "max_items": 20 },
  "capture": { "commit_token_threshold": 20000 },
  "labels": { "team": "search" }
}
KeyType / ValuesPurpose
peer.source"git" / "cwd" / "none" / template / list of templatesHow the workspace peer is derived; only a git repository gets one by default
peer.idstringPin the peer explicitly; takes precedence over peer.source
recall.enabledbooleanWhether the plugin recalls at all
recall.peer_scope"all" / "actor"all also sweeps this user's other peers, demoted in ranking; actor reads only user-level memories and this workspace's peer
recall.dedup_turnsinteger, 020Recent turns a recalled item is deduplicated against
recall.max_itemsinteger, 1100Maximum recalled items
recall.score_thresholdnumber, 01Minimum score for a recalled item
capture.enabledbooleanWhether the session is captured
capture.commit_token_thresholdinteger, 10001000000Tokens accumulated before a capture commits
bypass.session_patternslist of globsA session whose id or working directory matches skips recall and capture
labelsobjectFree-form metadata for humans; not read by the plugins

An out-of-range number is clamped to the nearest bound and reported; an unrecognized enum value is ignored. Keys outside this list are kept in the file and ignored.

Workspace Peer

A peer is a path prefix under your own user space — viking://user/<you>/peers/<peer>/memories — that keeps one project's memories together. By default only a git repository gets one: the normalized origin URL, else the repository root path. A directory that is not a repository sends no peer at all, and what is remembered there goes to your user-level space at viking://user/<you>/memories instead. That is deliberate: an application that opens a fresh directory for every task would otherwise mint a fresh, empty peer for every task.

peer.source decides the rule. The same setting is spelled OPENVIKING_PEER_SOURCE in the environment and plugin.peerSource or plugin.<harness>.peerSource in ovcli.conf.

Give a Directory Its Own Peer

Create .openviking/config.json in the directory:

json
{"version": 1, "peer": {"id": "my-project"}}

That directory and everything below it now writes to the peer my-project, repository or not. The id names no path, so it survives a move, a rename and a second machine — and two directories carrying the same id share one memory, which is how you merge them on purpose.

The other ways to set it, highest precedence first:

WhereWhat it does
OPENVIKING_PEER_ID=my-projectPins the peer for one process, whatever the files say
peer.id in .openviking/config.jsonNames this workspace's peer. The recommended way; config.local.json is the same key kept out of the commit
peer.source in the same fileDerives the peer instead of naming it — "cwd" for the directory path, "team-{dir}" for a template
plugin.peerSource in ovcli.conf, or OPENVIKING_PEER_SOURCEThe same choice for every directory on this machine; "cwd" restores the pre-git behavior everywhere
peer.sourceMeaning
"git"Default. The normalized origin URL, else the repository root path — equivalent to ["{git_remote}", "{git_root}"]. Outside a repository nothing is sent. No prefix is added.
"cwd"The working directory with every non-alphanumeric character replaced by -, byte for byte what earlier releases sent
"none"Send no peer at all; OPENVIKING_WORKSPACE_PEER=0 means the same
template / list of templatesFor example "git-{git_remote}" or ["{git_remote}", "team-{dir}"]; templates are tried in order, and one whose variables are empty falls through to the next
VariableValueEmpty when
{git_remote}Normalized origin, as github.com-org-repoOutside a git repository, or the repository has no origin
{git_root}Repository root path, with every non-alphanumeric character replaced by -Outside a git repository. A .openviking/config.json inside a repository still leaves this the repository's own root, so marking a subdirectory does not split the default peer
{cwd}Working directory, with every non-alphanumeric character replaced by -Never — and it is in no default chain, so a bare path becomes a peer only when you ask for one
{dir}The workspace root's directory name: the repository root, or the directory holding .openviking/config.jsonThe directory is not a workspace
{harness}The name of the agent running (claude-code, codex, dsh, opencode, pi, cursor, trae, trae-cn, zcode)Never — but the MCP proxy takes no part in derivation, so a read path that goes only through it cannot resolve it

In /Users/x/Dev/OpenViking/examples/codex-memory-plugin with origin [email protected]:volcengine/OpenViking.git, the peer is github.com-volcengine-openviking — the same value from any subdirectory, worktree, machine, or clone. Every clone of one repository therefore shares one peer, while a fork has a different origin and stays separate. The derivation reads the repository's files directly instead of running git, so it also works where git is missing from PATH, and the URL is normalized so that the ssh and https spellings of one repository agree and a token embedded in the URL never reaches the peer id.

By Situation

SituationWhat to do
A repository with an originNothing. Every clone, worktree and subdirectory shares one peer
A forkSeparate from upstream by default, because origin differs. To merge the two, write the same peer.id in both
A local repository with no remoteThe repository root path by default, which changes on another machine. For anything long-lived, write a peer.id
A long-lived directory that is not a repositoryCreate .openviking/config.json with a peer.id
One subproject of a monorepo needing its own memoryPut a config.json in the subdirectory with peer.source: "{git_remote}-{dir}". A marker file alone keeps the repository's peer, because {git_remote} resolves first
A throwaway task directory (a dated folder an app creates, an unpacked archive)Nothing. Its memories go to your user-level space
Each agent keeping its own memory of one repositorypeer.source: "{git_remote}-{harness}". Not the default — one shared project memory across agents is usually what you want, so this one is opt-in
Several directories sharing one memoryWrite the same peer.id in each
Not wanting per-project separation at allpeer.source: "none" (the same as OPENVIKING_WORKSPACE_PEER=0)

Recall Isolation

peer.source decides where memories are written; recall.peer_scope decides what is read back. A peer is a path prefix, not a tenant boundary. The same setting is spelled plugin.recallPeerScope in ovcli.conf and OPENVIKING_RECALL_PEER_SCOPE in the environment.

recall.peer_scopeWhat recall reads
"all" (default)User-level memories and this workspace's peer at full weight, plus a sweep across the user's other peers whose hits are demoted by category — the server's other_peer_penalty defaults to 0.1 for events and entities, 0.02 for preferences, experiences, resources and skills. Another project can therefore only ever come last
"actor"User-level memories and this workspace's peer only. The plugin additionally asks once for the peer the pre-git rule would have derived here, so nothing written by an earlier release is lost

User-level memories are read at full weight under both, and that is the cost of sending no peer outside a repository: what a throwaway task teaches is recalled in every project afterwards. For stronger separation, give such a directory a peer.id of its own, or switch to "actor".

Switching to the git default needs no migration and moves nothing: memories written under the earlier cwd-derived peer stay where they are, and recall keeps reaching them — through the cross-peer sweep under "all", and through the extra query under "actor". peer_scope is a per-request parameter; against a server too old to know it, the plugin records the downgrade once and warns rather than silently reading everything.

What a Workspace File May Not Set

A hook runs without a prompt, so these files are trusted; what is refused is structural instead:

  • Connection and credential keys — url, api_key, root_api_key, account, user, extra_headers, and the rest — are stripped with a warning wherever they appear. Which server the data goes to stays answerable from ovcli.conf and the environment alone.
  • ${VAR} is never expanded in these files.

What a committed file switches off is announced rather than blocked: the plugin's ov-memory-doctor reports every workspace-scoped value, the layer it came from, and what it shadowed.

.gitignore must not ignore all of .openviking/, or config.json can never be committed. Narrow the rule to the parser's scratch directories and the private file:

text
.openviking/media/
.openviking/downloads/
.openviking/config.local.json

ov-memory-doctor warns when a blanket rule is in effect.

The ov CLI directly uses only a small set of environment variables:

Environment VariablePurpose
OPENVIKING_CLI_CONFIG_FILESelect the ovcli.conf path
OPENVIKING_UPLOAD_MODESelect temporary upload mode: local or shared

The --api-key-env <name> and --root-api-key-env <name> options for ov config add and ov config edit read keys from a named environment variable and write them to the configuration.

Variables such as OPENVIKING_AUTO_RECALL, OPENVIKING_RECALL_LIMIT, OPENVIKING_AUTO_CAPTURE, and OPENVIKING_DEBUG are read by Agent plugin processes and are not ovcli.conf fields.

Multiple Servers

Normal ov commands, plus ov config show and ov config validate, resolve the effective configuration in this order:

  1. When OPENVIKING_CLI_CONFIG_FILE is set, that path is authoritative; a missing file is an error.
  2. When the variable is unset, the default active file:
text
~/.openviking/ovcli.conf

The interactive manager and ov config list, switch, add, edit, and delete always manage the default store. Named configurations in that store live next to the default active file:

text
~/.openviking/ovcli.conf.<name>

For example, a production configuration can contain:

json
{
  "url": "https://openviking.example.com",
  "api_key": "<production-api-key>",
  "timeout": 120
}

Common commands:

bash
ov config
ov config list
ov config switch <name>
ov config validate
ov config show

ov config switch <name> copies the named configuration to the default active file. If OPENVIKING_CLI_CONFIG_FILE remains set, normal ov commands continue to use the environment-selected file; unset it to use the switched default. New ov commands reread the effective file, while already-running Agent clients must restart before reading changes.

See OpenViking CLI Setup for interactive and agent-assisted configuration workflows.