Skip to content

feat: add config structs for services with inline env var config#1205

Merged
geoffjay merged 8 commits into
issue-1196from
issue-1197
May 13, 2026
Merged

feat: add config structs for services with inline env var config#1205
geoffjay merged 8 commits into
issue-1196from
issue-1197

Conversation

@geoffjay
Copy link
Copy Markdown
Owner

Creates dedicated config.rs modules for the six services that previously had all configuration read inline in main.rs: core, orchestrator, wrap, ask, notify, and communicate.

Each config struct follows the same pattern as the services migrated in #1204:

  1. Load base values from agentd_common::config::load()
  2. Overlay legacy AGENTD_* environment variables for backward compatibility
  3. Replace all inline env::var() calls in main.rs with config struct field access

The wrap and orchestrator backends continue to use BackendType::from_env_strict() for backend selection — that function already encapsulates AGENTD_BACKEND parsing with proper error messages.

Closes #1197

@geoffjay geoffjay added the review-agent Used to invoke a review by an agent tracking this label label May 12, 2026
Copy link
Copy Markdown
Owner Author

@geoffjay geoffjay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: feat: add config structs for services with inline env var config

Stack Position

This PR sits at the top of a blocked stack:

This PR cannot merge until the chain below it is resolved. The blocking issues in #1201 (AGENTD_HISTORY_SIZE collision, incomplete env var table, orchestrator rename) and the missing-test issue in #1203 propagate upward.


Blocking Issues

1. Silent config-file errors via unwrap_or_default() — all six new config.rs files

Same issue flagged in #1204. Every service's load() calls:

let shared = agentd_common::config::load().unwrap_or_default();

If the TOML config file is present but malformed, this silently returns Default::default() — the operator gets no error message, no log line, and no indication that their config was ignored. This will be extremely painful to debug in production.

Required fix in all six files (ask, communicate, core, notify, orchestrator, wrap):

let shared = agentd_common::config::load().unwrap_or_else(|e| {
    tracing::warn!(
        "failed to load config file, using compiled defaults: {e:#}"
    );
    agentd_common::config::AgentdConfig::default()
});

2. Diagnostic regression in crates/wrap/src/main.rs

The old main.rs had three explicit warn!() calls for invalid env var values:

warn!("AGENTD_WRAP_HISTORY_BYTES={:?} is not a valid usize; using default {} bytes", raw, DEFAULT_HISTORY_BYTES);
warn!("AGENTD_WRAP_CHANNEL_CAPACITY={:?} is not a valid usize; using default {}", raw, DEFAULT_CHANNEL_CAPACITY);
warn!("AGENTD_WRAP_CHANNEL_CAPACITY=0 is invalid; clamped to 1");

These were deleted in this PR but not moved into WrapConfig::load(). The new load() silently clamps or defaults bad values without telling the operator. The test test_channel_capacity_zero_clamped_to_one is a good sign — but a test passing silently doesn't help an operator who set AGENTD_WRAP_CHANNEL_CAPACITY=abc and wonders why their config was ignored.

Required fix — add warn! in WrapConfig::load() for each fallback:

// history_bytes
let history_bytes = std::env::var("AGENTD_WRAP_HISTORY_BYTES")
    .ok()
    .and_then(|v| {
        v.parse::<usize>().map_err(|_| {
            tracing::warn!(
                "AGENTD_WRAP_HISTORY_BYTES={v:?} is not a valid usize; using default {} bytes",
                DEFAULT_HISTORY_BYTES
            );
        }).ok()
    })
    .unwrap_or(base.history_bytes);

// channel_capacity (with clamp-to-1 warn)
let channel_capacity = std::env::var("AGENTD_WRAP_CHANNEL_CAPACITY")
    .ok()
    .and_then(|v| {
        v.parse::<usize>().map_err(|_| {
            tracing::warn!(
                "AGENTD_WRAP_CHANNEL_CAPACITY={v:?} is not a valid usize; using default {}",
                DEFAULT_CHANNEL_CAPACITY
            );
        }).ok()
    })
    .unwrap_or(base.channel_capacity);
let channel_capacity = if channel_capacity == 0 {
    tracing::warn!("AGENTD_WRAP_CHANNEL_CAPACITY=0 is invalid; clamped to 1");
    1
} else {
    channel_capacity
};

Non-Blocking Suggestions

crates/wrap/src/config.rs — TODO comments on hardcoded defaults

WrapConfig::load() falls back to DEFAULT_HISTORY_BYTES and DEFAULT_CHANNEL_CAPACITY constants rather than the shared schema fields (base.history_bytes, base.channel_capacity). This is expected given the schema gaps noted in #1201 (WrapConfig in shared schema is missing these fields). Leave a // TODO: use base.history_bytes once WrapConfig schema is complete comment so the gap is trackable.

crates/orchestrator/src/config.rs — unused port variable

There is a let port = ... binding that appears to be unused — it's computed but not stored in the returned OrchestratorConfig. Either include it in the struct or remove it to silence the dead-code warning.


What's Working Well

  • All test modules correctly acquire ENV_LOCK before mutating env vars
  • Save/restore/remove pattern is applied consistently: env vars are removed before the assert so a panic during setup doesn't leak state into other tests
  • The test_channel_capacity_zero_clamped_to_one test in wrap is a nice edge-case addition
  • Service-local config.rs modules are a clean separation from main.rs config wiring

Summary

Two blocking issues must be fixed before merge:

  1. All six load() functions need unwrap_or_else with a tracing::warn! instead of silent unwrap_or_default()
  2. WrapConfig::load() must restore the diagnostic warn!() calls that were removed from wrap/main.rs

This PR also needs a restack once #1201#1204 are resolved.

@geoffjay geoffjay added needs-rework PR has review feedback that must be addressed before merging and removed review-agent Used to invoke a review by an agent tracking this label labels May 12, 2026
@geoffjay geoffjay linked an issue May 12, 2026 that may be closed by this pull request
7 tasks
@geoffjay geoffjay added review-agent Used to invoke a review by an agent tracking this label and removed needs-rework PR has review feedback that must be addressed before merging labels May 12, 2026
geoffjay and others added 6 commits May 12, 2026 16:29
Add a ValidateConfig trait to agentd_common with implementations for all
12 shared config sections. Add AgentdConfig::validate() that collects
errors from every section. Implement ValidateConfig on all service-level
config structs and wire validate() into each service's startup path so
misconfigurations fail early with descriptive error messages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create dedicated config.rs modules for core, orchestrator, wrap, ask,
notify, and communicate. Each struct loads from agentd_common::config::load()
first, then overlays legacy AGENTD_* env vars for backward compatibility.
All inline env::var() calls in main.rs replaced with config struct access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add impl ValidateConfig for EmbeddingConfig and LanceConfig in
  crates/memory/src/config.rs (blocking gap: memory was the only service
  with no validation at startup)
- Wire validation in memory/main.rs: call validate() on embedding and
  lance configs, load shared config for port/host so port=0 is caught
  before any I/O with a clear error message
- Remove validate_inner() indirection in crates/index/src/config.rs;
  move logic directly into impl ValidateConfig for IndexConfig and
  import the trait in index/main.rs and the test module
- Make validate_url() pub in agentd-common so service crates can reuse
  it without duplicating the http/https check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ilures

Replace silent unwrap_or_default() with unwrap_or_else(|e| { tracing::warn\!(...) })
in all six new service config loaders (ask, communicate, core, notify, orchestrator,
wrap). Restore diagnostic warn\!() calls for invalid AGENTD_WRAP_HISTORY_BYTES and
AGENTD_WRAP_CHANNEL_CAPACITY env vars with TODO comments referencing #1201.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create docs/configuration.md with quick start, file location, precedence
  rules, complete key reference table, per-service sections, migration guide,
  and four example configs (minimal, development, production, Docker)
- Fix the env var table in agentd-common/config.rs to include all overrides
  (AGENTD_INDEX_LANGUAGES, AGENTD_RECONCILE_INTERVAL_SECS, all MCP URLs,
  AGENTD_NOTIFY_SERVICE_URL, AGENTD_COLLECTION_INTERVAL_SECS)
- Add link to configuration reference from README.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
geoffjay added 2 commits May 12, 2026 16:59
docs: add configuration system documentation
feat: add ValidateConfig trait and per-service validation
@geoffjay geoffjay merged commit 5b19e71 into issue-1196 May 13, 2026
@geoffjay geoffjay deleted the issue-1197 branch May 13, 2026 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-agent Used to invoke a review by an agent tracking this label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate services with inline env var config to shared TOML config

1 participant