Skip to content

Developer Guide

This guide is for ChatArch packages that want to use ChatEnv. ChatEnv owns typed env/profile mechanics; leaf packages own their service variables, connectivity tests, and runtime token semantics.

Responsibilities

ChatEnv provides:

  • EnvField for environment variable metadata.
  • BaseEnvConfig for typed schemas and automatic registry.
  • EnvStore for active .env and named profile files.
  • TokenStore for tokens/<Service>/<profile>.json runtime state with safe metadata.
  • chatenv CLI commands for env profiles and runtime tokens.
  • chatenv.configs discovery for schema providers.
  • chatenv.token_refreshers discovery for service-owned refresh hooks.

Leaf packages provide:

  • Their own BaseEnvConfig subclasses.
  • _aliases and _storage_dir.
  • chatenv.configs entry points.
  • Optional login/refresh functions registered through chatenv.token_refreshers.
  • Service-specific test() implementations.

Integrating a package

Depend on ChatEnv:

[project]
dependencies = [
    "chatenv>=0.2.8,<0.3.0",
]

Define a schema:

from chatenv import BaseEnvConfig, EnvField

class FooConfig(BaseEnvConfig):
    _title = "Foo Configuration"
    _aliases = ["foo", "chatfoo"]
    _storage_dir = "Foo"

    FOO_API_BASE = EnvField("FOO_API_BASE", desc="Foo API base URL")
    FOO_API_KEY = EnvField("FOO_API_KEY", desc="Foo API key", is_sensitive=True)

Register the provider:

[project.entry-points."chatenv.configs"]
chatfoo = "chatfoo.config"

Runtime token refresh providers

If a package needs access tokens, web sessions, cookies, or CSRF state, stable env/profile values should contain only re-authentication inputs. The runtime values should be generated by a service-owned refresh function:

[project.entry-points."chatenv.token_refreshers"]
Foo = "chatfoo.tokens:refresh_chatenv_token"
from chatenv import TokenRefreshResult

def refresh_chatenv_token(*, service, profile, home, env_store, token_store):
    return TokenRefreshResult(
        values={"access_token": "[REDACTED]"},
        token_type="oauth_access_token",
        summary={"account": "operator", "base_url": "https://foo.example"},
        expires_at="2026-08-11T23:00:00Z",
    )

chatenv token refresh Foo work invokes the hook and writes the token-store file. token import is only an explicit migration or external-refresh handoff path.

Local development

python -m pip install -e /path/to/ChatEnv
python -m pip install -e /path/to/chatfoo
chatenv status --detail
chatenv list
chatenv init -t foo -i
chatenv cat -t foo
chatenv test -t foo
chatenv test -t foo work
chatenv test -t foo --profile work

Reusable profile loading for future commands is available through EnvStore.load_config(config_cls, profile=None), which returns the loaded path. Active mode preserves legacy load_from_sources(env_values=...) overrides. Named mode uses BaseEnvConfig.load_from_profile(values) to assign literal file values and schema defaults, bypassing legacy source loaders that do not accept new keywords. A missing named profile raises FileNotFoundError. No arguments are added to provider test() methods.

test() receives the loaded target configuration. chatenv test -t foo work loads a named profile without activating it or filling missing fields from process environment or active values. Providers should inspect the loaded fields rather than reload default configuration inside test(). The shared load_from_sources(..., include_process_env=False) API supports the same isolated loading; omitting the option preserves process environment fallback.