Skip to content

Configuration

Docbank uses ~/.docbank/ with default settings unless you choose another vault. Use DOCBANK_HOME to select its location. Add config.toml when you need to change how the daemon runs.

The file controls the listening address, authentication, idle timeout, backup repository, watched inboxes, the optional MCP HTTP credential binding, and secondary-store connections. A vault with only a primary store needs no configuration file. Each registered secondary store needs a matching connection profile after restart. Backup commands need either a configured repository or a --repo flag.

For optional pinned local email rendering, see Email PDF configuration.

For optional bounded PDF and density-qualified PNG rendering, see Verified page images. The [page_runtime] section is independent of text and embedding providers.

Vault location

All data defaults to ~/.docbank/. Override with the DOCBANK_HOME environment variable:

export DOCBANK_HOME=/Volumes/Archive/docbank

Run docbank info after selecting a vault to see its canonical path and vault ID. This helps when one machine has several independent Docbank archives:

DOCBANK_HOME=/Volumes/Archive/docbank docbank info

The directory layout is created on first use:

~/.docbank/
├── docbank.db           # SQLite: virtual tree, metadata, FTS index
├── blobs/
│   ├── <aa>/<sha256>    # raw content-addressed document bytes
│   ├── <aa>/<sha256>.zst # managed compressed loose representation
│   └── tmp/             # staging for in-flight writes
├── email-pdf-spool/     # isolated email PDF input/output staging
├── logs/                # JSON logs from background daemons
├── web-launch/          # owner-private browser authentication handoff
├── web-downloads/       # private, temporary verified browser downloads
├── telemetry-install.json # anonymous telemetry install ID (with its .lock); created only while telemetry is on, kept if it is later turned off
├── telemetry-screen-views.json # daily screen claims; created only while telemetry is on
├── config.toml          # optional; see below
├── vault.lock           # advisory lock, held by a daemon or target restore
└── daemon.<pid>.json    # runtime record of a live daemon

docbank.db holds the local catalog, and blobs/ holds the built-in primary store. A .zst file contains compressed content. Hashes and document sizes always describe the decoded bytes. Docbank may compress new writes when the savings justify it, but it reads existing raw files without converting them.

Back up config.toml separately if you customize it. It can contain an api_key, filesystem paths, S3 coordinates, and credential-profile names.

vault.lock, daemon.<pid>.json, web-launch/, and web-downloads/ coordinate running processes. You can omit them from backups. Delete them only when no daemon or restore is running. docbank daemon stop removes its own runtime record on graceful shutdown.

Deleting telemetry-install.json while the daemon is stopped gives the vault a new anonymous install ID.

Use docbank backup create to capture every retained blob from a verified location, including content held only in a secondary store. The resulting backup can restore without recreating the original store layout.

A stopped copy of docbank.db and blobs/ is complete only when the primary is an authorized location for every retained blob. Copying config.toml saves secondary-store coordinates, but does not copy their content. Stop the daemon before taking a filesystem snapshot. See Vault lifecycle.

Docbank also keeps persistent per-user coordination files under ~/.local/state/docbank/target-locks, using the home directory from the operating-system account record. They contain no document data, but do not delete them. Daemons and restores use the files' stable identities to exclude overlapping vault trees, including simultaneous restores whose target trees overlap. They also use them to serialize daemon launch before the launcher owns or creates the vault root.

Warning

Don't edit or prune blobs/ or a secondary namespace by hand. The database authorizes physical files, including files for prior document versions. To reclaim space, use docbank trash empty --run, docbank gc --run, and (for dead packed payload) docbank storage repack. To check integrity, use docbank verify.

config.toml

$DOCBANK_HOME/config.toml is read once, at daemon startup (docbank daemon run / daemon start). docbank mcp --transport http also reads and validates the whole file at startup, then resolves its named credential binding. The file is optional. There are no general per-field environment overrides. DOCBANK_HOME selects the vault, and named credential bindings can read the environment variables that the configuration names. Backup commands can override their configured repository with --repo. The daemon treats an unrecognized key as a typo and rejects it at startup instead of ignoring it.

# ~/.docbank/config.toml — optional, defaults shown
[server]
bind_addr = "127.0.0.1"
api_port = 0          # 0 = ephemeral; clients discover the real port
                      # from the runtime record
api_key = ""          # empty = ephemeral per-run key (loopback only)
idle_timeout = "30m"  # background daemons only; "0" = never

[web]
enabled = true

[mcp.http]
credential_binding = "" # empty = HTTP MCP cannot start

[backup]
repo = ""           # no implicit repository; set a path or pass --repo
zstd_level = 0      # 0 = Kit default; otherwise 1-19

[storage]
pack_interval = "0"        # disabled; for example, "1h"
pack_max_bytes = 268435456  # 256 MiB soft raw-byte budget per run

[[watch]]
name = "agent-sessions"
source = "~/agent-sessions"
destination = "/archives/agents"
settle_time = "30s"
minimum_age = "168h" # optional; 7 days since source modification
scan_interval = "5s"
exclude = [".DS_Store", "cache/"]
  • bind_addr: the interface the API listens on. Loopback only (127.0.0.1, ::1, localhost): the API is plain HTTP, so a non-loopback bind would put the key and vault contents on the wire in cleartext. Reach a remote Docbank through an SSH tunnel or VPN.
  • api_port: 0 picks an ephemeral port. The CLI does not need to know it in advance, because it discovers the bound address from the daemon's runtime record.
  • api_key: the daemon checks X-Api-Key or Authorization: Bearer on every authenticated request. An empty setting makes the daemon generate a key at startup and publish it to same-user clients in the runtime record. Set a fixed key when a client cannot read that record, such as a client using an SSH tunnel from another machine.
  • idle_timeout: how long a background daemon waits without requests before exiting on its own. "0" disables idle shutdown. Foreground docbank daemon run ignores this and never idles out.
  • [web] enabled: serves the embedded web application at /. docbank web starts or reconnects to the compatible daemon and opens an authenticated browser session on a fresh per-daemon loopback origin, independent of a configured api_port. Disabling it 404s /, /photos, and /assets/. The API and /docs are unaffected. See Web application.
  • [mcp.http] credential_binding: names the separate inbound credential used by docbank mcp --transport http. An empty value leaves stdio available but makes HTTP startup fail. See MCP HTTP credential.
  • [backup] repo: default snapshot repository used when a backup command or API request omits repo. ~/... expands against the daemon user's home. A relative path is resolved beneath $DOCBANK_HOME. Keep the repository outside the live vault in normal deployments.
  • [backup] zstd_level: repository compression level. 0 uses Kit's default. Other values must be between 1 and 19.
  • [storage] pack_interval: schedules non-destructive packing of authorized loose blobs. "0" disables the schedule. A configured schedule runs once when the daemon starts and then at this interval.
  • [storage] pack_max_bytes: soft raw-byte budget for each scheduled run. It must be positive when pack_interval is enabled. Remaining loose content waits for a later run.

Scheduled packing is visible as the storage:pack job and keeps an auto-started daemon alive so the schedule can run. It uses the same maintenance gate as docbank storage pack: ordinary mutations may briefly receive maintenance_busy and can retry. Each scheduled pass requests cancellation at pack_interval and releases the gate when the pass returns. Remaining indexed loose content is retried on the next pass. Work that ignores context can delay gate release. Set pack_interval comfortably above the time needed to build and seal one pack so each pass can make progress. Repeated automatic packing canceled at interval; retrying warnings can indicate that the interval is too short. Automatic packing does not delete logical content and does not run GC or repack. An operator still has to request those reclamation operations.

MCP HTTP credential

The MCP HTTP listener requires a named credential binding. Configuration keeps only the environment-variable name. The bearer value stays in the MCP process environment:

[mcp.http]
credential_binding = "credential:mcp-http"

[credential_bindings.mcp-http]
environment_variable = "DOCBANK_MCP_HTTP_TOKEN"

Binding names start with a lowercase letter, contain only lowercase letters, digits, _, or -, and are capped at 63 characters. The configured environment-variable name must use ordinary shell-variable syntax. The bearer is non-empty, contains no spaces or control bytes, and is capped at 4,096 bytes.

Docbank resolves the bearer once when the MCP HTTP process starts. Changing the environment does not rotate a running process. The bearer must differ from [server] api_key and from an ephemeral daemon key published in the runtime record. HTTP startup acquires the effective daemon first and refuses a reused value. The same exclusion remains active if the daemon later restarts and the MCP process reacquires it.

There is no raw bearer field in config.toml, command-line token flag, URL credential, or runtime-record publication. Supply the environment variable to the MCP child through an owner-controlled secret or process manager. This is a fixed local bearer, not OAuth. See Model Context Protocol for the complete transport boundary.

Watched inboxes

Each [[watch]] entry makes the daemon poll one local directory recursively. source must be absolute or begin with ~/. destination is an absolute path in Docbank's virtual tree. Symlinks and other non-regular entries inside the source are ignored. exclude is a literal name-or-relative-path rule. It is independent of the glob include and exclude patterns accepted by docbank add.

Traversal stays on the source's filesystem mount. It does not enter symlinks, Windows directory reparse points, or nested mounts. Configure another [[watch]] entry when content on a separate mounted filesystem should also be imported. This boundary prevents an aliased vault directory from becoming its own input.

The daemon checks each file in this order:

  1. Observe the same filesystem object, size, and modification time for the complete settle_time.
  2. Require the source modification time to satisfy minimum_age, if enabled.
  3. Read the file, then check that the source path still names the same object. If it changed, do not accept the read as a Docbank node.

For example, minimum_age = "168h" requires a file to be at least seven days old and unchanged for the complete settle window. The default "0s" disables this age check. The source timestamp still applies after a daemon restart, but the in-memory settle observation starts again. This helps with sessions or recordings that pause before they finish.

scan_interval controls observation frequency. Zero settle and scan values select the defaults shown above. Any other value must be positive. minimum_age must not be negative.

Minimum age is a conservative time policy, not proof that the producing application closed a file. Choose a window appropriate to the producer, or watch a directory that receives only completed files when the producer offers a close/rename handoff.

A file that disappears during observation, or is still held exclusively by a Windows producer, is treated as unsettled and retried from a fresh window. Other read failures appear as job errors.

Docbank identifies each watched source by (name, relative source path). Keep the watch name when moving its local source root. Later content changes then add versions to the same Docbank node, even if someone moved that node in the virtual tree.

Renaming the relative source path creates a new source identity. Each identity owns one Docbank node, and two watched sources cannot claim the same node. Deleting a source file does not delete its Docbank node.

Docbank separately remembers the last bytes accepted from each source. If a person edits or reverts the Docbank node while the source stays unchanged, a daemon restart does not overwrite that working version. Only a later byte change at the watched source appends another version.

Watchers run as jobs named watch:<name>. docbank watch list and GET /api/v1/watches pair each runner's state with its effective source, destination, settle window, minimum source age, scan interval, and exclusion policy. Use --json when an agent needs the complete rules. docbank jobs and GET /api/v1/jobs remain the all-task view. A source, destination, or read failure leaves the named job in the failed state and records the reason. Restart the daemon after correcting the problem. Per-file successes are written to the daemon log. A configured watch keeps a background daemon alive regardless of idle_timeout.

Inspect the source facts recorded for an imported file with docbank provenance <path-or-id> or GET /api/v1/nodes/{id}/provenance. Provenance is distinct from job status. It survives daemon restarts and records where successfully ingested content came from, while docbank jobs describes only the current daemon run.

Watched inboxes never modify or delete their source files. Configuration is machine-local and is not part of metadata-v1 backup/restore. Portable metadata does preserve the watch name, relative path, node mapping, and last accepted content identity. The watcher does not pack content itself. Configure [storage] pack_interval when accumulated loose content should be packed automatically. GC and repack still run only on request.

Supplied audio transcription

The daemon can transcribe supplied WAV and MP3 files through a configured Docling Serve deployment. The profile's descriptor, artifact policy, filename disclosure, and trust boundary are portable. The endpoint, transport policy, and secret binding stay local to the daemon.

Use adapter_contract = "docbank-docling-asr/v1" and set credential_binding = "credential:<name>" on the rendition profile. Its runtime section requires endpoint, request_timeout, total_timeout, poll_interval, max_poll_attempts, allowed_cidrs, proxy_mode, and the transport timeout fields. spki_sha256 can pin the deployment certificate. The endpoint must be a root origin. allowed_cidrs must contain at least one network, and proxy_mode must be "disabled". HTTP endpoints require the operator_network trust boundary, and certificate pins require HTTPS. An explicit port must be between 1 and 65535. Redirects are not followed.

Set a positive max_transcript_chars on the rendition profile. This limit caps the generated transcript and is part of the descriptor's policy fingerprint. Each processing profile keeps its own max_document_chars limit for subsequent processing. A runtime with no selecting profile remains staged and isn't executable.

After a restart, queued work whose descriptor is no longer configured fails with stale_authority. Plan the work and grant consent for the changed profile before retrying it.

For this adapter, disclosure_fingerprint binds the descriptor, endpoint, and deployment fingerprint. Recompute it when the endpoint or deployment changes. The daemon rejects a mismatched binding before it starts provider work. Go applications can use docling.ASRDisclosureFingerprint from go.kenn.io/docbank/document/docling. Operators can compute the same value from their config with Python 3.11 or later. Replace the path and profile name in this command, then copy the output into that profile's disclosure_fingerprint:

python3 - /path/to/config.toml asr <<'PY'
import hashlib
import sys
import tomllib

with open(sys.argv[1], "rb") as source:
    profile = tomllib.load(source)["rendition_profiles"][sys.argv[2]]
values = [profile["adapter_contract"], profile["descriptor_id"],
          profile["descriptor_fingerprint"], profile["runtime"]["endpoint"],
          profile["deployment_fingerprint"]]
print(hashlib.sha256("\0".join(values).encode()).hexdigest())
PY

The daemon registers one provider per descriptor fingerprint. Profiles with the same descriptor must use identical endpoint, credentials, and runtime settings. Two Docling deployments with the same descriptor cannot run together in one daemon. Conflicting settings prevent startup.

The daemon also registers two local media profiles. supplied-transcript processes supplied WAV and MP3 transcript text as untimed evidence. supplied-captions processes supplied SubRip captions for WAV, MP3, and MP4 originals as timed evidence. Both names are reserved for these built-in profiles. A configured profile with either name prevents startup.

The daemon reads the credential from the named environment binding when the adapter sends a provider request. A missing secret fails that processing attempt but leaves supplied-media retention, plaintext processing, and the built-in supplied-transcript path available. Restart the daemon after changing the endpoint, transport policy, or environment binding.

Runtime field Meaning
endpoint Absolute root Docling Serve origin.
request_timeout, total_timeout Per-request and complete operation limits, each positive and at most 24 hours.
poll_interval, max_poll_attempts Delay and count bounds for polling. The interval cannot exceed total_timeout, and attempts range from 1 to 10,000.
allowed_cidrs, proxy_mode Non-empty IP network allowlist and proxy_mode = "disabled".
spki_sha256 Optional lowercase SHA-256 SPKI pins for the provider certificate; requires HTTPS.
connect_timeout, keep_alive, tls_handshake_timeout Positive transport limits, each at most five minutes.

Embedding workers and credentials

The daemon runs retained embedding jobs for its configured OpenAI-compatible and Voyage runtimes. Other provider packages are available to Go applications. The daemon cannot run them.

An embedding is a numeric representation used to compare document meaning. Each provider binding publishes its own results. One provider's failure does not remove another binding's completed vectors.

Configuring a provider does not prepare inputs or apply a processing profile to new imports. A job requires all of the following:

  • An existing input generation: the retained set of prepared provider inputs.
  • A matching processing profile.
  • A matching provider descriptor.
  • Current consent to disclose the inputs to that provider.

After restore, the daemon recreates jobs from retained inputs once these requirements are met again.

[processing_profiles.<name>] selects embedding bindings by name in its embeddings array. [embedding_profiles.<name>] defines each binding's model, input kind, dimensions, formatters, compatibility identity, descriptor and disclosure fingerprints, byte limits, and optional or required activation. Chunk bindings also pin their tokenizer and chunk policy in .chunk. Use the fingerprints from the provisioned profile and deployment. Arbitrary fingerprints or an endpoint's model alias do not establish compatibility.

Text-service configuration

For OpenAI-compatible text services, prefer Kit's [embedding_profiles.<name>.embedder] schema. Keep Docbank's pinned descriptor, consent, input kind, byte limits, normalization, model-input contract and chunk policy in the existing profile tables.

[embedding_profiles.semantic]
credential_binding = "credential:embedding-primary"
# The remaining pinned profile fields are also required.

[embedding_profiles.semantic.embedder]
base_url = "https://embedding.example.invalid/v1"
model = "provisioned-model"
dims = 768
fingerprint_salt = "deployment-v1"
batch_size = 8
timeout_seconds = 30
api_key = { env = "DOCBANK_EMBEDDING_PRIMARY_KEY" }

[embedding_profiles.semantic.runtime]
# Retain the provisioned egress policy and max_request_bytes.
# adapter_contract defaults to docbank-openai-compatible-embeddings/v1
# when embedder is present.

base_url ends in /v1 or /v1/embeddings. Public-IP HTTP endpoints are rejected. Plaintext private-network endpoints require trust_private_network = true. The existing CIDR and proxy controls still apply. The fingerprint_salt records the configured model revision. Unless a provider_revision_header is configured, it also supplies the deployment epoch.

The API key may be a literal string, { env = "NAME" }, or { file = "/absolute/path/to/private.key" }. Prefer environment or private-file references. Kit requires credential files to be private, regular files owned by the current user. File paths follow Kit's rules: ~/ expands to the daemon user's home, and relative paths use its working directory. Sources are resolved for each request. Startup does not read them. A missing secret becomes an authorization failure when that provider is used. File changes take effect on the next request. Environment changes require restarting the daemon.

Keep credential_binding as the portable name. The immutable profile records that name, not the secret or its source. If api_key is unset, an existing credential_bindings entry still supplies the secret. Without either source, startup reports that the credential source is not configured. Never put secret values in processing profiles, fingerprints, receipts, backups, or source-controlled configuration.

Kit's default batch size is 32 and its default timeout is 30 seconds. When converting a legacy configuration, set both values to the existing limits instead of relying on those defaults. The same effective settings produce the same canonical identities and reuse existing generations. Changing the model, revision or input recipe still requires a matching pinned descriptor and profile.

This adapter keeps Docbank's document/query formatting and chunk preparation. input_type_mode must be "none". Configure roles in model_input. model_context_tokens and max_batch_tokens must remain zero. Nonzero values are rejected because this adapter does not use Kit token packing. The profile's normalization setting still decides validation: adopting Kit's schema does not normalize returned vectors. unit_length requires the server to return unit vectors; Docbank rejects squared norms that differ from one by more than 1e-4.

Optional EmbeddingGemma 2 text recipe

Use the existing OpenAI-compatible adapter with a custom/v1 model-input contract for optional EmbeddingGemma 2 text retrieval. The Google model card specifies native 768-dimensional output and separate search-query and document prefixes. The recipe below targets Google's pinned checkpoint, google/embeddinggemma-2@914f7f89142e33e77833254d9c9b90c3cef7303b.

This is a fragment for a separately provisioned embedding profile. Retain its credential binding, egress policy, input and response bounds, chunk policy, descriptor ID, and formatter IDs. Set activation to optional if processing may continue without these embeddings. Recompute the immutable descriptor, authorization and disclosure fingerprints for the complete new profile; copied fingerprints from another model will fail daemon startup. Select the profile in a processing profile and review its processing plan before granting consent. See document processing configuration and the embedding runtime settings.

[embedding_profiles.semantic]
normalization = "unit_length"
compatibility_id = "embeddinggemma2/search/native768/v1"

[embedding_profiles.semantic.embedder]
base_url = "http://127.0.0.1:11434/v1"
model = "embeddinggemma2-text-f32-768-v1"
dims = 768
fingerprint_salt = "914f7f89142e33e77833254d9c9b90c3cef7303b-text-f32-mean-native768-v1"
input_type_mode = "none"
batch_size = 8
timeout_seconds = 30

[embedding_profiles.semantic.model_input]
profile = "custom/v1"
compatibility_id = "embeddinggemma2/search/native768/v1"

[embedding_profiles.semantic.model_input.document]
mode = "text"
template = "title: none | text: {{content}}"

[embedding_profiles.semantic.model_input.query]
mode = "text"
template = "task: search result | query: {{content}}"

The loopback endpoint and serving alias are examples. Provision the service separately. Its operator must bind the alias and deployment epoch to the exact weights, tokenizer, pooling, precision or quantization, and output-width recipe. fingerprint_salt records that assertion in the immutable revision and policy; it does not verify which weights the server loaded. Replace both the alias and epoch when that recipe changes, then create a matching descriptor and embedding generation. Keep the epoch equal to the resolved model revision, or use the existing revision-header contract instead.

Docbank applies each template once and preserves its space before {{content}}. The server must accept these already formatted strings without adding prompts again. Require mean pooling including the prompts, L2-normalized output, and bfloat16 or float32 activations, never float16. The server must enforce the shared 8,192-token input window, including formatting, and the agreed truncation policy. Reserve prompt overhead in the chunk budget. A character limit, batch size, or byte limit does not enforce tokenizer admission.

dims declares the expected response width. This adapter sends neither dimensions nor input_type, and it never slices or normalizes the result. Wrong-width, nonfinite, zero-norm cosine, and non-unit vectors are rejected. Reduced 512-, 256-, or 128-dimensional output requires an explicit custom serving contract that truncates and then L2-renormalizes both documents and queries, plus a new matching descriptor, compatibility identity and generation. The current adapter has no request_dimensions option. Put literal formatting in model_input; unsupported embedder affix keys are rejected at load time.

The native model recipe is verified against primary sources, and synthetic HTTP tests exercise configuration, literal formatting, identity and vector validation. Actual model inference, checkpoint loading, tokenizer admission, pooling, precision, server prompt behavior and retrieval quality remain untested. This recipe transports rendition text and text queries only; it does not advertise original-file image, audio or video support. No default model or existing generation changes when this fragment is staged.

Legacy text-service configuration

Existing model, dimensions, max_batch_items, runtime endpoint, model_revision, request_timeout, and named environment credentials remain supported. Prefer the embedder table for new text-service configurations. Native and multimodal providers retain their existing configuration.

If both forms specify a setting, their effective values must agree. For example, embedder.dims = 768 conflicts with dimensions = 1024. If api_key is set and a named credential entry also exists, both must reference the same environment variable. Otherwise remove the legacy entry when switching sources. Profiles that share a credential name must agree on its source.

[credential_bindings.embedding-primary]
environment_variable = "DOCBANK_EMBEDDING_PRIMARY_KEY"

[embedding_profiles.semantic]
credential_binding = "credential:embedding-primary"
# The remaining pinned profile fields are also required.

A missing or empty secret leaves ordinary document operations available. Affected embedding jobs record an authorization failure and can recover later. Startup still fails for an undefined legacy credential binding, invalid runtime configuration, or mismatched descriptor.

Runtime settings

An optional [embedding_profiles.<name>.runtime] section makes a binding executable on this machine. Without it, the daemon does not claim that binding's work. Runtime configuration and credential sources are machine-local and must be supplied separately after restoring a vault.

Fields Meaning
adapter_contract docbank-openai-compatible-embeddings/v1 for rendition chunks, or docbank-voyage-embeddings/v1 for original files.
endpoint, model_revision Exact provider endpoint and pinned revision. OpenAI-compatible endpoints are origins without a path; Voyage uses https://api.voyageai.com/v1.
deployment_epoch, provider_revision_header OpenAI-compatible runtimes require exactly one. The epoch must equal model_revision; a revision header must echo the pinned revision in every response.
capability_manifest Voyage requires an absolute path to a capability manifest matching its model, media policy, and descriptor.
request_timeout, max_request_bytes Bound each provider request. The profile's max_batch_items, max_input_bytes, and max_response_bytes supply the other request/response limits.
allowed_cidrs, spki_sha256, proxy_mode Explicit destination CIDRs, optional TLS public-key pins, and proxy_mode = "disabled". The provider connection enforces this policy.
connect_timeout, keep_alive, tls_handshake_timeout Required positive transport durations, each at most five minutes.

Request timeouts must also be positive and at most five minutes. Retry policy belongs to the worker, so runtime configuration has no retry-count or retry-delay fields. The worker handles transient failures and capacity-driven batch splits. It records malformed responses separately from rejected document input.

Model input

[embedding_profiles.<name>.model_input] pins how document and query inputs are formatted. Its profile selects a named contract such as nomic/v1, bge-m3/v1, e5/v1, or gte/v1. It is not an arbitrary provider model name. The resulting contract must match the binding's compatibility_id and provider descriptor. For custom/v1, supply compatibility_id plus .document and .query encoders, each with mode and template. Templates use {{content}}. Contract validation checks the supported roles and formatting rules. query_instruction is available only to contracts that support it.

Discovery reads in pages and waits one minute between complete passes. Existing queued work is still checked on the normal one-second idle cadence. Discovery skips missing or invalid generation bytes so later candidates can proceed, and a later pass retries them. Database failures keep their separate bounded storage-retry behavior. Terminal jobs do not retain superseded generations after their last embedding set is collected, while queued/running jobs and explicit retention roots keep their inputs.

Search reranking

A processing profile can opt into one hosted reranking adapter. The section is deployment configuration, so it stays outside the portable document profile and does not change rendition or embedding identities.

[credential_bindings.search-rerank]
environment_variable = "DOCBANK_SEARCH_RERANK_KEY"

[processing_profiles.private.reranking]
provider = "zeroentropy"
model = "zerank-2"
credential_binding = "credential:search-rerank"
candidate_count = 20
excerpt_bytes = 4096
deadline = "5s"
failure_policy = "degrade"
endpoint = "https://api.zeroentropy.dev"
allowed_cidrs = ["192.0.2.0/24"]
proxy_mode = "disabled"
connect_timeout = "5s"
keep_alive = "30s"
tls_handshake_timeout = "5s"

provider can be zeroentropy with model zerank-2, or cohere with rerank-v4.0-pro or rerank-v4.0-fast. candidate_count must be between 1 and 1,000. excerpt_bytes must be between 1 and 4,096 and limits each UTF-8 excerpt sent to the provider. deadline must be positive and at most five minutes. failure_policy is degrade or fail_closed.

The daemon rejects a partial section, an unknown model, an invalid endpoint or egress policy, and an undefined credential binding. It reads the named secret only when a reranking request reaches the provider. The provider call needs an active query-and-excerpt consent grant. The adapter policy fingerprint binds the provider, model, candidate limit, excerpt limit, deadline, endpoint, and transport policy to the reviewed plan.

Adding this section changes the plan fingerprint and makes the plan report consent required until reranking is approved. Existing grants remain valid for the operations they already cover, including searches without --rerank. Granting the revised plan approves all configured profile operations together. Reranking has its own grant record, but no separate approval step. Follow the search consent walkthrough to review and grant the revised plan.

Self-hosted Cap origins

Register a self-hosted Cap deployment under [media_origins.<name>]. The endpoint is a single HTTP(S) origin. Cap share and embed paths are recognized only on that origin. The deployment revision, credential binding, network allowlist, TLS pins, and probe timeout are part of the daemon configuration.

[credential_bindings.team-cap]
environment_variable = "CAP_API_KEY"

[media_origins.team-cap]
provider = "cap.self-hosted"
endpoint = "https://cap.example.test"
allowed_cidrs = ["127.0.0.0/8"]
proxy_mode = "disabled"
connect_timeout = "30s"
keep_alive = "30s"
tls_handshake_timeout = "10s"
spki_sha256 = []
credential_binding = "credential:team-cap"
deployment_revision = "v-synthetic"
probe_timeout = "30s"

HTTPS uses the system trust store. A private deployment may use HTTP when its configuration lists allowed CIDRs. The daemon resolves the named credential only for the registered origin and runs a bounded probe at startup. Recognized recordings remain access_required. Docbank has no byte download path for them.

Registration affects new submissions. A generic source retained earlier stays separate from a later registered-origin submission.

Store bindings

[store_bindings.<name>] profiles describe machine-local filesystem or S3-compatible secondary storage. Filesystem profiles use kind = "filesystem" and an absolute path. S3 profiles use kind = "s3", endpoint, region, bucket, optional prefix, credential_profile, and force_path_style. priority controls read preference after current health. Lower values are preferred. The complete workflow and examples are in Multi-store storage.

Bindings are loaded once when the daemon starts. Logical metadata, audit evidence, and backups do not include them. Restart after editing a profile. Docbank reports a typed stale-configuration error instead of hot-reloading credentials or paths underneath active jobs.

S3 endpoints must use authenticated HTTPS, including loopback services. Docbank rejects plain HTTP: a loopback port does not identify which process receives an ownership marker or document bytes.

Active stores must use separate locations:

  • A filesystem root must not overlap the vault, a watched inbox, or another filesystem store.
  • S3 prefixes must not be equal or nested within the same canonical endpoint and bucket.

Docbank also checks each store's ownership marker and epoch, a value that identifies the current ownership claim. These checks catch aliases that path comparisons cannot recognize.

Secondary objects are verified but not encrypted by Docbank. Raw readers of a filesystem root or S3 prefix can decode document content without the daemon API key. Store profiles therefore belong only on owner-controlled storage, or on storage protected by independently controlled filesystem, bucket, or KMS encryption and access policy.

Bind validation

The daemon validates its listening address at startup. An invalid setting makes docbank daemon run fail immediately:

  • A loopback bind_addr (127.0.0.1, ::1, localhost) is the only accepted value. An empty api_key is fine there: the daemon generates one at startup instead.
  • Every non-loopback address (wildcard, private-network, or public, keyed or not) is rejected. The API is plain HTTP, so a key sent in cleartext is not protection. Remote access goes through an SSH tunnel or VPN to the loopback listener until the daemon grows TLS.

Environment variables

Variable Effect
DOCBANK_HOME Vault location; see Vault location above.
DOCBANK_LOCK_DIR Absolute lock-registry directory for an isolated environment whose account home is unwritable. Defaults to the operating-system account home's .local/state/docbank/target-locks, independent of HOME and XDG settings. All processes sharing or restoring overlapping vault trees must use the same directory; stop them before changing this setting. Keep it outside vaults and restore targets. Never delete it while any participating process runs.
DOCBANK_LOG_LEVEL Log level (debug, info, warn, error) for docbank daemon run and docbank mcp, foreground or background. Invalid values are ignored and fall back to info.
DOCBANK_TELEMETRY_ENABLED 0, false, no or off turns off anonymous usage telemetry. Read when the daemon starts; restart the daemon after changing it.
TELEMETRY_ENABLED The same values have the same effect; shared with other Kenn tools.

Anonymous usage telemetry

The daemon reports anonymous usage events so the Docbank team can count active vaults, web app opens, and screens used in the browser and terminal UI. Counts are per vault, not per person: one person with three vaults counts three times. The daemon sends events in HTTPS batches to PostHog's US ingest endpoint (PostHog project 434713). The browser never contacts PostHog: the web app posts its event to its own daemon, which sends it.

Docbank sends these events:

  • daemon_started and daemon_active at each daemon start, then daemon_active on the first hourly check of each later UTC day. Days when the machine sleeps are not backfilled. A background daemon exits after idle_timeout (30 minutes by default) and starts again on the next command, so most of these go out at a daemon start, and daemon_started counts starts rather than installs.
  • app_opened when the web app loads, and again on the first window focus of a later UTC day. The browser remembers the day for the daemon's address, so it sends about one per UTC day until the daemon restarts on a new address.
  • session_ended once when a browser tab closes or stays hidden for 30 minutes, or the terminal browser exits, including when its terminal closes. Browser visible time adds up across tab switches. Hidden time is excluded. The terminal browser counts the time from opening to exit, including idle time. A terminal browser left idle past the daemon's idle timeout reports nothing on exit because it sends the report only to a running daemon.
  • screen_viewed with a fixed screen name and surface of web or tui. Each screen counts once per vault per UTC day for each interface, including across daemon restarts. surface records which interface was used. The daemon rejects other screen or surface names with HTTP 400.

The daemon remembers which screen events it has queued today in memory and in telemetry-screen-views.json beside the install ID. If it cannot queue an event, that screen remains eligible for another attempt. Remote delivery is best effort.

Allowed screen values are browse, search, tags, snapshot, history, versions, provenance, jobs, audit_evidence, storage, backups, bates, export, saved_queries, collections, trash, tag_catalog, telemetry, term_reports, processing, rendition, upload, mailbox, load_file, snapshot_actions, help, document, packages, operations.

Each event carries these fields:

  • the event name, a random event UUID, and a timestamp
  • distinct_id: a random install ID generated on this machine
  • application=docbank, source=daemon, the Docbank version and commit, goos, goarch, and install_age_hours (whole hours since the install ID was created)
  • $process_person_profile=false and $geoip_disable=true
  • fields the PostHog Go library adds: $lib, $lib_version, $os, $os_version, $os_distro (Linux only), and $go_version
  • session_ended also carries surface as web or tui and duration_bucket as under_1m, 1_to_5m, 5_to_30m, or over_30m

Usage telemetry never carries document content, filenames, paths, hashes, tags, queries, the vault ID, account names, the hostname, or configuration values. PostHog does see the request's source IP address. Docbank asks it not to geolocate. Separately configured document providers are unrelated to usage telemetry and unchanged by it.

The install ID lives in telemetry-install.json at the vault root (see the layout above). The daemon creates it the first time it runs with telemetry on, and never while telemetry is off. Each vault has its own ID.

To opt out, set DOCBANK_TELEMETRY_ENABLED=0 (or TELEMETRY_ENABLED=0) in the environment that starts the daemon, then run docbank daemon restart. A CLI command that starts the daemon automatically passes its own environment, so set the variable in your shell profile. Go applications that embed a vault in-process send nothing.