Configuration
Codumentor is configured through a YAML configuration file, typically named codumentor.yaml. This file controls various aspects of the system including repositories to analyze, file patterns to include/exclude, model settings, and tool behavior.
Which configuration guide is this? This is the complete operator reference — every option, including authentication, the API server, logging, and config inheritance. If you just want a single-user instance running quickly, start with the shorter Setup → Configuration. To stand up a team/production instance end-to-end, follow the Self-Hosting Walkthrough.
Tip — edit config from a chat. Instead of hand-editing this YAML, admins can use the Configuration Assistant: an admin-only chat (Admin page → Configuration Assistant) that changes the running instance's config in plain language. It grounds itself in this reference and the live schema, validates the change, shows you the exact YAML diff and whether it applies live / needs a restart, and only writes after you approve — with a timestamped backup and one-step rollback. Enable it with the
configuration_assistantplugin.
Environment Variable Substitution
All string values in the configuration file support environment variable substitution using ${VAR_NAME} syntax. This allows you to keep sensitive values (like API keys) or environment-specific paths out of your configuration files.
Example:
models:
agent: "${AGENT_MODEL}"
agent_base_url: "${BASE_URL}/v1"
embedding_api_key: "${GOOGLE_API_KEY}"
vector_db:
path: "${DATA_DIR}/vector_db"
repos_dir: "${REPOS_DIR}"
Environment variables are substituted when the configuration is loaded. If a variable is not set, the original ${VAR_NAME} string is kept as-is.
Note: Environment variable substitution works for all string values throughout the configuration, including nested dictionaries and list items.
Config inheritance with extends
You can let one config build on another using the extends key. The value can
be a relative path (resolved from the file that declares it) or an absolute
path. Extends are applied depth-first: parents load first, then the child
overrides them.
# child.yaml
extends: base.yaml # or a list: [base.yaml, extras/feature.yaml]
models:
agent: "gemini-2.0-pro" # overrides the parent value
vector_db:
path: "./data/vector_db_variant" # override while inheriting other settings
Cycles are detected and raise an error. Extends works together with the CLI
-c/--config merging: each file is resolved with its own extends chain, then
the resulting configs are merged in the order you pass on the CLI.
Configuration File Structure
The configuration file uses the following structure:
repos:
- "https://github.com/user/repo1.git"
- "path/to/local/repo2"
repos_dir: "repos"
# include_patterns: [] # Empty by default — all known file types are included
# exclude_patterns use sensible defaults (see below)
ingestion:
max_file_size: 1048576 # 1 MB (default) — skip files larger than this
chunking:
size: 1000
overlap: 100
models:
embedding: "text-embedding-004"
embedding_base_url: "https://generativelanguage.googleapis.com/v1beta/openai/"
agent: "gemini-2.0-flash"
agent_base_url: "https://generativelanguage.googleapis.com/v1beta/openai/"
vector_db:
backend: "chroma"
path: "./data/vector_db"
cache:
embedding_enabled: true
embedding_db_path: null
embedding_max_age_days: 365
agent:
max_iterations: 10
storage_dir: "./data/agent_storage"
tools:
tool_result_max_content_length: 30000 # Max chars before tool output is chunked
shell_output_max_size: 10240
file_listing_max_size: 10240
shell_timeout: 900
shell_always_allow: false
search_concurrency: 5
api:
host: "127.0.0.1"
port: 2638
reload: false
enable_web_ui: true # Serve the protocol-native /ui/* API + SPA
enable_openai_api: false # Legacy OpenAI-compatible /v1/* surface (opt-in)
stream_flush_ms: 250 # Coalesce streamed deltas into one UI event per beat (0 = per-chunk)
stream_flush_bytes: 4096 # Flush the delta buffer early once it reaches this size
ui:
welcome_title: "Welcome to Codumentor"
welcome_description:
en: "Your self-hosted AI coworker."
hu: "Önállóan üzemeltethető AI munkatárs."
disabled_extensions: []
auth:
provider: "none" # Options: "none", "gitea"
gitea:
base_url: "https://gitea.example.com"
token_cache_ttl_minutes: 30 # Token cache TTL in minutes
prompt:
template_dir: "prompts"
system_prompt_template: "system_prompt.jinja2"
max_iterations_notification_template: "max_iterations_notification.jinja2"
custom_instructions: []
debug_mode: false
show_tool_calls: true
logging:
level: "INFO"
file: "./logs/codumentor.log"
logger_levels: {}
plugins:
- module: "codumentor.plugins.filesync"
class: "FileSyncPlugin"
Configuration Options
repos
List of repositories to analyze. Entries can be either simple strings (Git URLs or local paths) or structured objects that describe alternative SCM providers:
repos:
# Git support (string form)
- https://github.com/example/project.git
# Explicit configuration for alternate SCMs provided by plugins
- scm: svn
url: https://svn.example.com/repos/legacy
name: legacy_svn
options:
branch: trunk
# Pin to a branch/commit
- url: https://github.com/example/project.git
branch: release # or commit: <sha> / pin: <tag>
# Inline ref pin using URL suffix (common git syntax)
- https://github.com/example/project.git@release
- https://github.com/example/project.git#v1.2.3
# Use an existing local checkout
- path: /opt/shared/repo
branch: feature/search # optional: will checkout this ref before ingestion
# Pre-synced directories (requires filesync plugin)
- scm: filesync
name: shared_docs
path: "\\\\fileserver\\engineering\\docs"
scm(optional) selects the repository provider. Defaults to"git".urlis used for network-backed repositories (Git, SVN, etc.).pathcan point to an existing local directory. Pair with thefilesyncplugin if the directory should be synchronized from a remote share before ingestion.nameoverrides the derived repository name used inside Codumentor.optionsis a free-form dictionary passed to custom SCM plugins.branch/commit/pinlet you lock a repository to a specific ref (checked out after clone/update).- Inline pin format is supported on git URLs:
https://...repo.git@branchor...git#tag.
Plugins can register additional SCM providers (e.g., "svn", "filesystem") to handle these entries during ingestion.
Generic *_overrides
Any top-level key can have a companion <key>_overrides entry. After configs
are merged (and env vars substituted), overrides are applied automatically:
- Dictionaries: deep-merged into the base dictionary
- Lists of named items (dicts with a
namekey): matched by name and deep-merged; unmatched entries are appended - Other lists: appended to the base list
- Other types: replace the base value
repos_overrides entries can be plain URL strings (same formats accepted by
repos) — they are normalized to dicts before merging.
Examples:
# base.yaml
logging:
level: INFO
logger_levels:
codumentor.tools: WARNING
repos:
- name: kb
url: https://example.com/kb.git
branch: main
# variant.yaml
logging_overrides:
json_logging: true
logger_levels:
codumentor.tools: ERROR
codumentor.agent: DEBUG
include_patterns_overrides:
- "**/*.md"
repos_overrides:
# Match existing repo by name — only override the branch
- name: kb
branch: feature-branch
# Add a new repo using a plain URL string
- ssh://git@gitea.example.com:2244/org/sandbox.git
# Add a new repo with full dict syntax
- scm: svn
url: "https://svn.example.com/trunk"
name: legacy-svn
logging keeps level: INFO, enables JSON logging, and merges logger levels.
include_patterns gains the additional patterns while preserving the base ones.
repos gets the kb repo's branch updated to feature-branch, plus two new
repos appended.
##### Nested *_overrides
*_overrides also works deeper than the top level, using the same merge
rules. This is handy for surgically overriding one item in a nested list of
named items — e.g. a single LDAP directory under auth.ldap_directories —
without restating the whole list (a plain dict merge would replace it).
A nested <key>_overrides entry merges into its sibling <key> when present;
when <key> is absent (e.g. a parent config dropped it), the override applies
to an empty base, so list entries are added and dict values are set directly.
Because any key ending in _overrides is treated as a merge directive at
every level, config field names must never end in _overrides.
# base.yaml
auth:
provider: ldap
ldap_directories:
- name: corp
server_url: ldaps://corp.example.com
bind_dn: cn=svc,dc=corp
bind_password: pw
base_dn: dc=corp
security_mode: ldaps
- name: partner
server_url: ldaps://partner.example.com
bind_dn: cn=svc,dc=partner
bind_password: pw
base_dn: dc=partner
# variant.yaml — flip only the corp directory to STARTTLS
auth:
ldap_directories_overrides:
- name: corp
security_mode: starttls
corp keeps every other field and switches to starttls; partner is
untouched. An override entry whose name is not present is appended as a new
directory.
plugins
Codumentor supports plugins to extend functionality. Plugins are configured as a list of plugin specifications:
plugins:
- module: "codumentor.plugins.filesync"
class: "FileSyncPlugin"
- module: "codumentor.plugins.mcp"
class: "MCPPlugin"
args:
executable: "python"
args: ["-c", "from mssql_mcp_server import main; main()"]
module: Python module path to import the plugin class fromclass: Class name to instantiateargs: Optional dictionary of arguments to pass to the plugin constructorpriority: Optional priority for hook ordering (default: 100)
Workspace Isolation Plugin
The workspace isolation plugin sandboxes each conversation session using Linux bubblewrap with overlay filesystems. It requires bubblewrap (compiled with overlay support), an overlayfs-capable kernel, and — on Ubuntu 24.04+ — an AppArmor profile; see Plugins in Production → Workspace isolation prerequisites for the install steps.
plugins:
- module: codumentor.plugins.workspace_isolation
class: WorkspaceIsolationPlugin
priority: 5
args:
enabled: true
workspace_ttl: 86400 # 24 hours
persistent_home: true # Persistent, shared $HOME (default: true)
subagent_isolation: shared # "shared" (default) or "isolated"
sandbox:
unshare_net: true # Block networking inside sandbox (default)
Key options:
| Option | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable/disable workspace isolation |
workspace_ttl | int | 86400 | Workspace time-to-live in seconds |
persistent_home | bool | true | Bind-mount a persistent HOME (<workspace>/home/) instead of tmpfs. When true, $HOME survives across sandbox invocations and is shared among the main agent, subagents, and external agents. Set to false for legacy ephemeral HOME. |
subagent_isolation | str | "shared" | "shared": subagents share the main agent's sandbox (simple, recommended). "isolated": each subagent gets its own sandbox with VCS integration and merge conflict resolution. |
sandbox | dict | {} | Sandbox hardening (see plugin README) |
repos_dir
Base directory where repositories will be cloned and stored.
include_patterns and exclude_patterns
File patterns using gitignore-style glob syntax. These control which files are
considered for ingestion. Files must also pass binary detection and the
max_file_size limit (see ingestion below).
include_patterns (default: [] — empty)
When empty (the default), all files with known extensions are included
automatically. Codumentor recognizes ~180 file extensions covering source code,
config files, templates, markup, and documentation. Files with unknown
extensions are still included if they pass a binary-detection heuristic (first
8 KB checked for null bytes and printable-byte ratio).
When non-empty, only files matching at least one pattern are included (whitelist
mode, for backward compatibility).
exclude_patterns (broad defaults)
# Default exclude_patterns:
exclude_patterns:
- "**/.git/**"
- "**/.svn/**"
- "**/.hg/**"
- "**/node_modules/**"
- "**/vendor/**"
- "**/packages/**"
- "**/.nuget/**"
- "**/__pycache__/**"
- "**/venv/**"
- "**/.venv/**"
- "**/*.egg-info/**"
- "**/.tox/**"
- "**/.mypy_cache/**"
- "**/.pytest_cache/**"
- "**/bin/**"
- "**/obj/**"
- "**/dist/**"
- "**/build/**"
- "**/out/**"
- "**/target/**"
- "**/.idea/**"
- "**/.vscode/**"
- "**/.vs/**"
- "**/.env/**"
- "**/coverage/**"
- "**/htmlcov/**"
- "**/*.min.js"
- "**/*.min.css"
Pattern syntax:
*.py— matches Python files in the root directory*/.py— matches Python files recursivelysrc/— matches everything under thesrcdirectory
Important: Setting include_patterns or exclude_patterns in your config
replaces the defaults entirely. To append patterns without losing the
defaults, use the _overrides suffix instead:
# REPLACES defaults — you lose all built-in excludes:
exclude_patterns:
- "**/my_custom_dir/**"
# APPENDS to defaults — built-in excludes are preserved:
exclude_patterns_overrides:
- "**/my_custom_dir/**"
The same applies to include_patterns_overrides.
ingestion
Controls document ingestion behavior:
max_file_size: Maximum file size in bytes (default: 1048576 = 1 MB). Files larger than this are skipped during ingestion. Set to0to disable the limit. Useful for excluding generated bundles, minified files, and large logs.streaming_threshold: Number of chunks above which streaming mode is used for stored file info retrieval (default: 10000)file_processing_batch_size: Number of files to process per batch during change detection (default: 1000)
chunking
Controls how documents are split into chunks for vector storage:
size: Target characters per chunk (default: 1000). A 200-character budget is reserved for the metadata prefix added during embedding, so effective chunk size issize - 200.overlap: Number of overlapping characters between chunks (default: 100)
models
Model configuration for different AI services:
embedding: Model ID for embedding generationembedding_base_url: Base URL for embedding APIembedding_max_input_length: Max input characters for the embedding model (optional). Overrides the built-in lookup table when set. Use this for local/unknown models, e.g.1700for a 512-token model.agent: Model ID for the main agentagent_base_url: Base URL for agent APIjudge: Model ID for evaluation/judging (optional, falls back to agent settings)judge_base_url: Base URL for judge API (optional)
API keys can be specified in the configuration or through environment variables:
api_key: General API key (fallback for all models)agent_api_key: Agent-specific API keyembedding_api_key: Embedding-specific API keyjudge_api_key: Judge-specific API key
Note: API keys support environment variable substitution using ${VAR_NAME} syntax (e.g., embedding_api_key: "${GOOGLE_API_KEY}"). See Environment Variable Substitution above for details.
Thinking/Reasoning Mode:
agent_thinking_enabled: Enable model thinking/reasoning mode (default:false). Whentrue, sendsenable_thinking: trueto the model viachat_template_kwargsand filters<think>...</think>blocks from the response shown to users. Works with both vLLM (which separates thinking into areasoningfield via--reasoning-parser) and external providers where thinking appears inline in content. Recommended for Qwen3.5 and similar models that support thinking mode. Example:agent_thinking_enabled: trueagent_show_thinking: Show captured thinking content in the UI as a collapsible block above each assistant message (default:false). Requiresagent_thinking_enabled: true. When disabled (the default), thinking is silently discarded after filtering — enabling it lets users inspect the model's reasoning. Short blocks (≤400 characters) open expanded; longer ones start collapsed. The user's last open/close action is remembered for subsequent blocks within a session. Example:agent_show_thinking: trueagent_reasoning_passback: Echo capturedreasoning_contentback to the API on subsequent requests (default:false). DeepSeek v3.2+ (e.g.deepseek-v4-pro) requires this on assistant turns that includetool_calls— without it the API returns400 "The reasoning_content in the thinking mode must be passed back to the API."Safe to enable for any provider that supports thereasoning_contentfield on assistant messages: DeepSeek and Qwen via vLLM/SGLang accept it (vLLM/SGLang silently drop it on input). Leavefalsefor providers that don't recognise the field (most Gemini/OpenAI/Anthropic-compatible endpoints), since they may reject the request. Example:agent_reasoning_passback: trueagent_reasoning_field: Field name used when echoing reasoning back (default:"reasoning_content"). Override only if your provider uses a different name. Example:agent_reasoning_field: "thinking"
HTTP Timeouts:
read_timeout: HTTP read timeout in seconds for streaming responses (default: 300). This is the maximum time allowed between chunks during streaming. Increase for slow models, models with long thinking phases, or high-latency endpoints (e.g., RunPod). Example:read_timeout: 600
Model Profiles (per-subagent model selection):
By default, all subagents use the same model as the main agent. Model profiles let you assign different models to different subagent types — for example, a powerful reasoning model for the main agent and a cheaper, faster model for subagents.
A profile is a named bundle of model configuration: model ID, endpoint, API key, and optional parameters. Profiles are defined under models.profiles and referenced by name from subagent_default (applies to all subagents) or subagent_profiles (per-tool assignments).
models:
agent: "claude-sonnet-4-20250514"
agent_base_url: "https://api.anthropic.com/v1/"
agent_api_key: "${ANTHROPIC_KEY}"
profiles:
local-fast:
model: "qwen3-8b"
base_url: "http://localhost:8000/v1/"
api_key: "none"
cloud-cheap:
model: "gpt-4o-mini"
base_url: "https://api.openai.com/v1/"
api_key: "${OPENAI_KEY}"
# Default profile for all subagents
subagent_default: "local-fast"
# Per-tool assignments (take precedence over subagent_default)
subagent_profiles:
explore: "local-fast"
subagent: "cloud-cheap"
web_retrieve:
model: "gpt-4o"
base_url: "https://api.openai.com/v1/"
api_key: "${OPENAI_KEY}"
Resolution order: subagent_profiles[tool_name] > subagent_default > global agent settings.
Override values can be a profile name (string) or an inline profile definition (dict). When a profile omits api_key, the global agent API key fallback chain is used.
Available profile fields:
model(required): Model ID stringbase_url(required): API endpoint URLapi_key: API key (optional — falls back to global agent key)extra_body: Extra parameters merged into every request (e.g.,chat_template_kwargs)thinking_enabled: Enable thinking/reasoning mode (default:false)show_thinking: Show thinking content in the UI (default:false)reasoning_passback: Echoreasoning_contentback to the API (default:false). Required for DeepSeek v3.2+ thinking models when used with tools.reasoning_field: Field name for reasoning passback (default:"reasoning_content")rdc_injection_method:"user_message"or"system_message"(default:"user_message")read_timeout: HTTP read timeout in seconds (default: 300)
Known subagent tool names: subagent, explore, agentic_developer, web_retrieve, web_search, context_summarization.
speech
Speech-to-text / text-to-speech service used by the read_aloud message action and Telegram voice replies. It is a sibling of models, not part of it, because the audio provider is usually a different endpoint than the chat-model gateway (e.g. a local vLLM box serves chat but not Whisper/TTS). Uses OpenAI-compatible audio endpoints (/v1/audio/transcriptions, /v1/audio/speech).
speech:
enabled: true
base_url: "https://api.openai.com/v1"
api_key: "${OPENAI_API_KEY}"
tts_model: "tts-1"
tts_voice: "alloy"
| Field | Default | Description |
|---|---|---|
enabled | false | Master switch. The web read_aloud action lights up only when this is true and api_key resolves to a real value. |
base_url | https://api.openai.com/v1 | OpenAI-compatible audio endpoint base URL. |
api_key | null | Supports ${ENV_VAR} and ${secret:<name>}. Use an ${ENV_VAR} for read-aloud / the Telegram bot: a per-user ${secret:...} only resolves inside an agent turn, so it cannot drive the out-of-turn web read-aloud call. |
stt_model | whisper-1 | Speech-to-text model. |
stt_language | null | null = let the provider auto-detect the spoken language. |
stt_max_audio_bytes | 26214400 (25 MB) | Reject larger uploads before hitting the provider. |
tts_model | tts-1 | Text-to-speech model. |
tts_voice | alloy | TTS voice. |
tts_format | opus | opus → Ogg/Opus (native Telegram voice note). Also: mp3, aac, flac, wav, pcm. |
tts_speed | 1.0 | Playback speed multiplier. |
tts_max_input_chars | 4096 | Guard against synthesising an enormous reply. 0 disables it. |
read_timeout | 120.0 | HTTP read timeout (seconds). |
max_retries | 2 | Retry count for transient provider errors. |
See Plugins in Production → Speech for the operational checklist.
vector_db
Vector database configuration:
backend: Vector database backend to use (default: "chroma")path: Storage path for the vector database (default: "./data/vector_db")
cache
Embedding caching configuration:
embedding_enabled: Whether to enable embedding caching (default: true)embedding_db_path: SQLite database path for embedding cache (auto-determined if null)embedding_max_age_days: Maximum age for embedding cache entries (default: 365)
agent
Agent behavior configuration:
max_iterations: Maximum number of agent iterations (LLM calls with tool responses) per query (default: 10)storage_dir: Base directory for agent storage files (default: "./data/agent_storage")enable_subagents: Whether to enable subagent functionality (default: true)isolate_subagent_scratchpad: When false (default), subagents share the parent agent's conversation scratchpad so they can read and write shared state (e.g.files_accessed,repos_mentioned). When true, each subagent receives its own isolated scratchpad.
tools
Tool-specific configuration:
tool_result_max_content_length: Maximum characters for any single tool output before it is automatically chunked and made pageable viaread_content(default: 30000). This universal limit applies to all tools — file reading, shell output, @-references, web retrieval, and any plugin output. Previously namedfile_reader_max_content_length.shell_output_max_size: Maximum size (in bytes) for shell command output before truncation (default: 10240)file_listing_max_size: Maximum size (in bytes) for file listings (default: 10240)shell_timeout: Timeout in seconds for shell command execution (default: 900)shell_always_allow: Whether to always allow shell commands without confirmation (default: false)search_concurrency: Maximum number of per-repository searches to run in parallel (default: 5)
api
OpenAI-compatible API server configuration:
host: Host to bind to (default: "127.0.0.1")port: Port to bind to (default: 2638)reload: Whether to enable auto-reload for development (default: false)
ui
Web UI customization:
welcome_title: Title shown on the conversation opening page. Can be a plain string (used for all languages) or a locale map.welcome_description: Description shown below the title. Same format aswelcome_title.disabled_extensions: List of plugin IDs whose UI extensions should be hidden (default:[]).
When welcome_title or welcome_description are not set, the built-in translated defaults are used.
Plain string (same text for every language):
ui:
welcome_title: "Welcome to ACME CodeBot"
welcome_description: "Ask questions about our internal services and libraries."
Per-locale map (i18n):
ui:
welcome_title:
en: "Welcome to ACME CodeBot"
hu: "Üdvözöl az ACME CodeBot"
welcome_description:
en: "Ask questions about our internal services and libraries."
hu: "Kérdezz a belső szolgáltatásainkról és könyvtárainkról."
You can mix the two styles — for example a plain welcome_title with a locale-mapped welcome_description.
auth
Authentication configuration for API access:
provider: Authentication provider to use (default: "none")"none": No authentication required (local development only)"gitea": Use Gitea personal access tokens for authentication"local": Username/password users defined directly in config"ldap": Use LDAP/Active Directory for authentication- (
"test"exists for the test suite only — never use it in a real deployment) ui_provider/api_provider: Optional per-surface overrides.ui_providertakes precedence overproviderfor the UI;api_provideroverrides the API when set, otherwise inheritsui_provider. See Authentication.jwt_secret: Deployment-wide secret that signs persistent login sessions and seeds at-rest encryption for theuser_secrets/model_profiles/oauthstores. Read it from an env var ("${CODUMENTOR_JWT_SECRET}"). When the env var is unset the placeholder is dropped with a loudERROR, sessions become ephemeral, and those stores are written unencrypted. See Authentication → jwt_secret.none.default_roles: Roles granted to the anonymous user whenprovider: none(default:["user"]).
See the Authentication guide for the full per-provider reference.
Gitea Provider
gitea.base_url: Base URL for Gitea instance (required when provider is "gitea")gitea.token_cache_ttl_minutes: Token validation cache TTL in minutes (default: 30)- Caches successful validations to reduce Gitea API calls
- Set to
0to disable caching - Recommended range: 15-120 minutes for production use
- Security Note: Only valid tokens are cached; invalid tokens are never cached
Local Provider
A fixed set of username/password users defined in config. The simplest way to give a small team real logins without Gitea or LDAP:
auth:
provider: local
jwt_secret: "${CODUMENTOR_JWT_SECRET}" # keep persistent sessions across restarts
local:
users:
- username: admin
password: "${CODUMENTOR_ADMIN_PASSWORD}" # plaintext or pbkdf2_sha256$ hash
email: admin@example.com
roles: ["admin", "user", "power_user"]
- username: dev
password: "${CODUMENTOR_DEV_PASSWORD}"
roles: ["user"]
Each entry takes username (required, unique), password (required — plaintext or a pbkdf2_sha256$... hash, ${ENV_VAR} substitution supported), and optional email, display_name, and roles (default ["user"]). Generate a hash with python -c "from codumentor.auth.providers.local import hash_password; print(hash_password('s3cret'))". See Authentication → Local for details.
LDAP Provider
For enterprise environments using LDAP or Active Directory:
auth:
provider: ldap
ldap:
# Connection settings (required)
server_url: "ldaps://ldap.example.com" # or ldap:// for non-SSL
bind_dn: "cn=service,dc=example,dc=com"
bind_password: "${LDAP_BIND_PASSWORD}"
base_dn: "dc=example,dc=com"
# Server type: "active_directory", "openldap", or "generic"
server_type: "openldap"
# Security: "ldaps" (SSL), "starttls", or "none"
security_mode: "ldaps"
# User search settings
user_search_filter: "(&(objectClass=inetOrgPerson)(uid={username}))"
user_search_base: "ou=users,dc=example,dc=com" # defaults to base_dn
username_attribute: "uid" # "sAMAccountName" for AD
email_attribute: "mail"
display_name_attribute: "displayName"
# Group settings (for role mapping)
group_search_base: "ou=groups,dc=example,dc=com"
group_member_attribute: "memberOf"
# Role mapping: LDAP groups → Codumentor roles
group_role_mapping:
"cn=admins,ou=groups,dc=example,dc=com": ["admin"]
"cn=developers,ou=groups,dc=example,dc=com": ["developer"]
default_roles: ["user"]
# Optional: require membership in a specific group
require_group: "cn=codumentor-users,ou=groups,dc=example,dc=com"
# SSL certificate validation
validate_cert: true
ca_cert_file: "/path/to/ca-cert.pem" # optional
Active Directory defaults (when server_type: active_directory):
user_search_filter:(&(objectClass=user)(sAMAccountName={username}))username_attribute:sAMAccountNamegroup_search_filter: Uses AD's nested group resolution
OpenLDAP defaults (when server_type: openldap):
user_search_filter:(&(objectClass=inetOrgPerson)(uid={username}))username_attribute:uid- Nested group resolution disabled by default
Multiple LDAP directories. Replace the ldap: block with a list under
ldap_directories: to authenticate against several independent directories.
Each entry takes the full set of LDAP options shown above plus a unique
name. On login the directories are tried in declared order; the first
successful bind wins. See Authentication
for the routing rules, identity behaviour, and audit-log labelling.
auth:
provider: ldap
ldap_directories:
- name: corp
server_url: "ldaps://corp.example.com"
# ... full LDAP options ...
- name: contractors
server_url: "ldaps://contractors.example.com"
# ... full LDAP options ...
prompt
Prompt/template system configuration (see Prompt System for the full reference):
template_dir: Directory containing prompt template files (default: "prompts"). Override at runtime with--prompt-dir.system_prompt_template: System prompt template file (default: "system_prompt.jinja2")max_iterations_notification_template: Template for max iterations notification (default: "max_iterations_notification.jinja2")custom_instructions: Additional custom instructions to include in promptsdebug_mode: Whether to enable debug mode for prompt templates (default: false)show_tool_calls: Whether to show tool call descriptions in the output stream for both main and subagents (default: true). When true, tool calls will be shown to the user on the API.
tools
Tool-specific configuration:
shell_output_max_size: Maximum size (in bytes) for shell command output (default: 10240)file_listing_max_size: Maximum size (in bytes) for file listings (default: 10240)shell_timeout: Timeout in seconds for shell command execution (default: 900)shell_always_allow: Whether to always allow shell commands without confirmation (default: false)disable_vector_search: Whether to disable vector database search functionality (default: false)search_concurrency: Maximum number of per-repository searches to run in parallel (default: 5)
When disable_vector_search is set to true, the agent will not use the vector database for semantic search, relying instead on other methods like file reading and shell commands to find information.
scheduler
Controls the scheduler — the component that fires recurring and one-off jobs onto the job queue (scheduled agent runs, periodic reports, ingestion refresh, etc.).
The scheduler shares its SQLite file with the job queue (jobs.sqlite3 by default, overridable via CODUMENTOR_JOBS_DB_PATH). WAL is enabled automatically.
scheduler:
enabled: true
idle_poll_interval: 30.0 # max seconds between loop ticks when idle
disable_after_failures: 5 # consecutive infra failures before auto-disable
max_catchup_age: 86400.0 # 24h — skip fires older than this
max_schedules_per_user: 100
default_timezone: "UTC"
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Master switch. When false, the scheduler loop never starts and schedule_* operations will fail. Existing schedules remain in the DB. |
idle_poll_interval | float | 30.0 | Maximum seconds the loop sleeps between ticks when no fires are imminent. Lowering this costs a bit more DB I/O; raising it delays reaction to newly-created schedules up to this bound. |
disable_after_failures | int | 5 | After this many consecutive infrastructure failures (e.g. database is locked on enqueue), the schedule is auto-disabled and its status becomes disabled. Handler exceptions do not count — they mark the fired job failed, not the schedule. |
max_catchup_age | float | 86400.0 | If the scheduler has been offline and a scheduled fire is older than this many seconds, skip it silently and jump to the next occurrence. Prevents firing a week-long backlog of stale runs after an outage. |
max_schedules_per_user | int | 100 | Cap on active+paused schedules per owner_user_id. Protects against unbounded growth if users can create schedules interactively. |
default_timezone | str | "UTC" | Default IANA timezone for schedules that don't specify one. |
Routing. By default, scheduled fires land on the shared agent_runs job queue. Plugins that need per-user isolation can pass a per-user queue name at schedule creation (target_queue=f"agent_runs_{user_id}"). Be aware that each distinct queue name spawns its own processor task — don't multiply them casually.
Disabling at runtime. Set enabled: false and restart. Schedules persist in the DB and resume when re-enabled. To stop a single schedule without touching config, use scheduler.pause(id) or scheduler.cancel(id) from code.
See Scheduler Guide for the plugin-developer view and firing semantics.
webhooks
Push-notification webhook endpoint — lets Gitea/GitHub trigger ingestion automatically. See Webhooks for full setup.
enabled: Master switch. Whenfalse(default) the endpoint returns 404.secrets: List of accepted shared secrets. The request is accepted if any entry matches. Supports environment substitution (${VAR_NAME}) and zero-downtime rotation (add new, remove old). Leaving this empty whileenabled: truereturns 503.
webhooks:
enabled: true
secrets:
- "${CODUMENTOR_WEBHOOK_SECRET}"
- "${CODUMENTOR_WEBHOOK_SECRET_PREVIOUS}"
logging
Logging configuration:
level: Base log level (default: "INFO")file: Log file path (default: "./logs/codumentor.log")logger_levels: Logger-specific log levels that override the base levelcategory_levels: Backward compatibility for logger levels (maps to logger_levels)console: Optional boolean. If set, controls whether log lines are also written to standard error in every mode (API server, CLI, TUI). If omitted, Codumentor chooses a default: the API process logs to stderr as well as the log file; CLI and TUI log only to the file so stdout/stderr stay free for command output and the terminal UI. Setconsole: trueto mirror API-style logging during local CLI/TUI runs, orconsole: falseto keep API logs file-only (for example when a process manager already tails the log file).
Built-in log rotation. Codumentor can rotate the log file itself (a TimedRotatingFileHandler), independent of an external logrotate:
logging:
level: INFO
file: ./logs/codumentor.log
rotation_enabled: true
rotation_when: midnight # "midnight", "H" (hourly), "D" (daily), "W0".."W6", "S", "M"
rotation_interval: 1 # rotate every N of the above unit
rotation_backup_count: 30 # keep this many rotated files
rotation_utc: true # compute rollover times in UTC
| Field | Default | Description |
|---|---|---|
rotation_enabled | false | Enable timed rotation of the log file. |
rotation_when | "midnight" | Rollover unit (Python TimedRotatingFileHandler codes). |
rotation_interval | 1 | Number of rotation_when units between rollovers. |
rotation_backup_count | 30 | How many rotated files to retain; older ones are deleted. |
rotation_utc | true | Use UTC when deciding rollover boundaries. |
JSON logging (for ELK/Splunk/Datadog — see also Deployment → JSON Logging):
| Field | Default | Description |
|---|---|---|
json_logging | false | Emit structured one-line-JSON logs. |
json_log_file | null | Separate file for JSON logs. If unset, JSON is written alongside the text log. |
json_include_context | true | Include the per-record context dict (session id, etc.). |
json_include_stack_info | false | Include stack info on records that carry it. |
json_include_process_info | false | Include process/thread identifiers. |
json_date_format | null | Override the timestamp format. |
The text file handler (and the JSON handler when enabled) is always configured when a log file path is set.