Skip to content

Tracking: single owner for configuration #183

Description

@ecalifornica

From @akesling in #174 review:

...we should probably fix whatever our config loading system is reading from and use something within a controllable context instead of the nasty global mutable singletons which are env vars. Are we using figment or something yet? If not, that's probably our next step: moving to a model where there's a single, testable, owner of all configuration we're loading. Global mutation of process environment variables like this won't play nice with parallel execution of tests, etc.

Current state

  • Code reads environment variables at ~40 locations, at all depths:
    • config.rs::config_dir()
    • seven provider PathResolvers, constructed at ~30 locations in path-cli
    • reader flags inside parse loops (CODEX_ROLLOUT_STRICT, CLAUDE_CLI_DEBUG)
    • GITHUB_TOKEN in toolpath-github
  • Tests must change the process environment and hold two locks.
  • This is not safe with parallel tests. Sandbox harness resolver env vars in the resume test suite #174 is the most recent patch for this problem.

Goal

  • run() reads the environment one time.
  • Figment converts the values into one immutable Config.
  • All code below run() receives values as parameters.
  • Library crates do not read the environment.
  • Users see no change: same variables, same precedence.

Phase 1: figment reads env. Values flow inward.

  • Add Config at the composition root
  • Remove env reads from the provider crates
  • toolpath-github: pass credentials as a parameter
  • Remove the test env machinery. Add a lint.

Phase 2

  • Add a toml layer: ~/.toolpath/config.toml, below env

Phase 3

  • Add clap as the top figment layer
    • Only config-type flags join. Positional arguments are data, not config.

Related, separate issue

  • Support CLAUDE_CONFIG_DIR and CODEX_HOME
    • Today we do not read them, so we fail to find relocated sessions.
    • Do this after Config exists.

Decisions

  • Resolver constructor: new(home), required argument, same shape in all seven crates. Per-crate with_* builders stay for overrides.
  • PATHBASE_URL keeps its name. The figment env layer reads it explicitly.
  • Config is passed as a parameter: &Config into command entry points, plain values across library boundaries. No global store.

Out of scope

  • pathbase-app. Per CLAUDE.md it consumes these crates with ^0.y version ranges, so breaking minor bumps do not reach it until it upgrades. If that description is wrong, we fix pathbase with PRs there.
  • Figment profiles.
  • Custom providers, with one exception: an env provider that emits values as verbatim strings. Config field types are the single type authority.
  • std::env::current_dir() and std::env::temp_dir() reads stay in place. Tests control them with explicit path arguments, so they do not have the global-mutation problem that env vars have.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions