Configuration Assistant Plugin
The configuration_assistant plugin gives administrators a chat that edits this Codumentor instance's own configuration in plain language — "add this repo", "switch the main model to the fast slot", "enable the redmine plugin and tell me what secret it needs", "why are webhooks failing?" — instead of hand-editing YAML against the configuration reference.
It runs against the running instance itself (target = self) using curated, in-process tools that read and write the real config file directly. The full design rationale is in doc/core-dev/design/configuration-assistant.md.
How it works
The plugin does not add a new agent surface. Instead, an admin-only launcher on the Admin page creates a normal conversation stamped with metadata.agent_profile = "config_assistant" and opens it in the standard chat UI (so streaming, approvals, and the rest are reused). A run-last onPromptAssemble hook then, only for those conversations:
- swaps in a focused system prompt, and
- replaces the visible tool list with a curated allowlist of seven config tools (the inverse of the goal-worker denylist) — a narrow blast radius.
Ordinary conversations are untouched.
Tools
| Tool | Approval | Purpose |
|---|---|---|
config_schema | none (read) | Introspect the live pydantic Config (keys, types, defaults) joined with each section's hot-reload class (🟢 live / 🟡 rebuild / 🔴 restart). Generated from the code, so it cannot go stale. |
config_read | none (read) | The current resolved config (env-substituted; secret values redacted). |
config_docs | none (read) | The prose docs (doc/admin/configuration.md) on demand — list topics, then fetch a section. |
read_logs | none (read) | Tail / grep the configured log file (logging.file) to diagnose problems. |
config_propose | none (read) | Build a candidate change, dry-run validate it, and return the exact YAML diff + each changed section's reload class. Writes nothing. |
config_apply | write_system_config | Re-validate, back up, write the leaf config atomically, then hot-reload. |
config_rollback | write_system_config | Restore the most recent timestamped backup and reload. |
Write tools declare a PermissionRequest, so they flow through the runtime's PermissionProvider exactly like any other side-effectful tool — the admin approves the diff before anything is written. Every tool also refuses to run outside a config-assistant conversation (defense-in-depth).
The safety flow
config_apply never reimplements reload. One turn looks like:
- Ground —
config_read+config_schema+config_docs. - Propose —
config_proposeruns the real loader pipeline (withoutsys.exit) to validate, then returns a unified YAML diff and the reload class. An invalid change is reported with the precise error and never offered for apply. - Approve —
config_applyis gated; the admin approves the diff. - Apply — backup → atomic write →
ConfigReloadManager.reload(). The resultingReloadReport(applied/rebuilt/restart_required/errors) is surfaced verbatim. - Rollback —
config_rollbackrestores the last backup and reloads.
Configuration
plugins:
- module: codumentor.plugins.configuration_assistant
class: ConfigurationAssistantPlugin
args:
enabled: true
No other settings. The plugin edits the leaf instance config (the last file in CODUMENTOR_CONFIG_FILES).
Access control
Access is gated at the conversation-creation route (POST /ui/plugins/configuration_assistant/conversations) by require_permission("admin:*") — only an admin can create a config-assistant conversation. Because the activation hook keys off that metadata, activation implies admin; the curated tools are never registered on an ordinary user's conversation.
Reload classes
What a change costs is taken from config/reload/semantics.py and shown up front:
- 🟢 live — read fresh on each use; applies immediately (e.g.
tools,ui,branding). - 🟡 rebuild — a subsystem reactor runs to apply it (e.g.
models,agent,prompt,plugins,logging,repos). - 🔴 restart — written but not applied at runtime; needs a process restart (e.g.
api,auth,vector_db,cache,ingestion).
Notes & limitations
- Comments are not preserved on write. Phase 1 writes with PyYAML, which drops comments/formatting. Every write is preceded by a timestamped
<config>.bak.<UTC>next to the leaf file, andconfig_applysays so;config_rollbackrestores it. The proposed diff is computed against normalized YAML, so it shows only the semantic change, not comment churn. (Comment-preserving round-trip is a future enhancement.) - Secrets are not written in Phase 1. The assistant detects a needed per-user /
${secret:…}secret and points the admin at Settings → User Secrets; it does not set secrets itself. - Edits target the leaf file, not deeper files in an
extends:chain. - See the design doc's Implementation status for what shipped and the deliberate deviations.