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:
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:
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:0picks 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 checksX-Api-KeyorAuthorization: Beareron 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. Foregrounddocbank daemon runignores this and never idles out.[web] enabled: serves the embedded web application at/.docbank webstarts or reconnects to the compatible daemon and opens an authenticated browser session on a fresh per-daemon loopback origin, independent of a configuredapi_port. Disabling it 404s/,/photos, and/assets/. The API and/docsare unaffected. See Web application.[mcp.http] credential_binding: names the separate inbound credential used bydocbank 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 omitsrepo.~/...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.0uses Kit's default. Other values must be between1and19.[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 whenpack_intervalis 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:
- Observe the same filesystem object, size, and modification time for the
complete
settle_time. - Require the source modification time to satisfy
minimum_age, if enabled. - 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 emptyapi_keyis 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_startedanddaemon_activeat each daemon start, thendaemon_activeon the first hourly check of each later UTC day. Days when the machine sleeps are not backfilled. A background daemon exits afteridle_timeout(30 minutes by default) and starts again on the next command, so most of these go out at a daemon start, anddaemon_startedcounts starts rather than installs.app_openedwhen 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_endedonce 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_viewedwith a fixedscreenname andsurfaceofwebortui. Each screen counts once per vault per UTC day for each interface, including across daemon restarts.surfacerecords 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 machineapplication=docbank,source=daemon, the Docbankversionandcommit,goos,goarch, andinstall_age_hours(whole hours since the install ID was created)$process_person_profile=falseand$geoip_disable=true- fields the PostHog Go library adds:
$lib,$lib_version,$os,$os_version,$os_distro(Linux only), and$go_version session_endedalso carriessurfaceaswebortuiandduration_bucketasunder_1m,1_to_5m,5_to_30m, orover_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.