diff --git a/README.md b/README.md
index a62da82..64ae157 100644
--- a/README.md
+++ b/README.md
@@ -811,6 +811,7 @@ Config file: `~/.nanobot/config.json`
OpenAI Codex (OAuth)
Codex uses OAuth instead of API keys. Requires a ChatGPT Plus or Pro account.
+No `providers.openaiCodex` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
**1. Login:**
```bash
@@ -845,13 +846,14 @@ nanobot agent -c ~/.nanobot-telegram/config.json -w /tmp/nanobot-telegram-test -
-Github Copilot (OAuth)
+GitHub Copilot (OAuth)
-Github Copilot uses OAuth instead of API keys. Requires a [Github account with a plan](https://github.com/features/copilot/plans) configured.
+GitHub Copilot uses OAuth instead of API keys. Requires a [GitHub account with a plan](https://github.com/features/copilot/plans) configured.
+No `providers.githubCopilot` block is needed in `config.json`; `nanobot provider login` stores the OAuth session outside config.
**1. Login:**
```bash
-nanobot provider login github_copilot
+nanobot provider login github-copilot
```
**2. Set model** (merge into `~/.nanobot/config.json`):
diff --git a/nanobot/cli/onboard_wizard.py b/nanobot/cli/onboard_wizard.py
index 2537dcc..eca86bf 100644
--- a/nanobot/cli/onboard_wizard.py
+++ b/nanobot/cli/onboard_wizard.py
@@ -664,6 +664,7 @@ def _get_provider_info() -> dict[str, tuple[str, bool, bool, str]]:
spec.default_api_base,
)
for spec in PROVIDERS
+ if not spec.is_oauth
}
diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py
index 607bd7a..c884433 100644
--- a/nanobot/config/schema.py
+++ b/nanobot/config/schema.py
@@ -78,7 +78,7 @@ class ProvidersConfig(Base):
volcengine_coding_plan: ProviderConfig = Field(default_factory=ProviderConfig) # VolcEngine Coding Plan
byteplus: ProviderConfig = Field(default_factory=ProviderConfig) # BytePlus (VolcEngine international)
byteplus_coding_plan: ProviderConfig = Field(default_factory=ProviderConfig) # BytePlus Coding Plan
- openai_codex: ProviderConfig = Field(default_factory=ProviderConfig) # OpenAI Codex (OAuth)
+ openai_codex: ProviderConfig = Field(default_factory=ProviderConfig, exclude=True) # OpenAI Codex (OAuth)
github_copilot: ProviderConfig = Field(default_factory=ProviderConfig, exclude=True) # Github Copilot (OAuth)
diff --git a/tests/test_commands.py b/tests/test_commands.py
index 6020856..124802e 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -213,6 +213,15 @@ def test_config_matches_openai_codex_with_hyphen_prefix():
assert config.get_provider_name() == "openai_codex"
+def test_config_dump_excludes_oauth_provider_blocks():
+ config = Config()
+
+ providers = config.model_dump(by_alias=True)["providers"]
+
+ assert "openaiCodex" not in providers
+ assert "githubCopilot" not in providers
+
+
def test_config_matches_explicit_ollama_prefix_without_api_key():
config = Config()
config.agents.defaults.model = "ollama/llama3.2"
diff --git a/tests/test_onboard_logic.py b/tests/test_onboard_logic.py
index fbcb4fb..9e0f6f7 100644
--- a/tests/test_onboard_logic.py
+++ b/tests/test_onboard_logic.py
@@ -359,6 +359,8 @@ class TestProviderChannelInfo:
assert len(names) > 0
# Should include common providers
assert "openai" in names or "anthropic" in names
+ assert "openai_codex" not in names
+ assert "github_copilot" not in names
def test_get_channel_names_returns_dict(self):
from nanobot.cli.onboard_wizard import _get_channel_names