# NousResearch/hermes-agent · Adding config get/unset/remove subcommands and fixing docs

## Open now

- 1 issue, 1 PR open on GitHub.
- #59598: hermes config set: missing 'remove' subcommand
- PR #59632: feat(cli): add \`hermes config remove <key>\` subcommand (#59598)

These issues and PRs concern adding missing subcommands to 'hermes config' (get, unset, remove) to complete its CRUD surface. Several members also address documentation that references 'hermes config get <key>' as if it were a valid command when it may not exist.

## TL;DR

- 15 member(s): 1 open issue(s), 2 closed issue(s), 1 open PR(s), 1 merged PR(s), 10 PR(s) closed without merging.
- A fix was merged to main in PR #65540. Verify it addresses your case.
- **Recommended:** read PR #65540 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-65540`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.12`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Open related issues

- #59598: hermes config set: missing 'remove' subcommand

## Closed / duplicate issues

- #30195: docs: \`hermes config get <key>\` referenced in 3 guides is not a valid command
- #36037: \[Feature\]: hermes config get <key> and config unset <key> — complete the config CRUD surface

## Prior & competing PRs

- **#65540: feat(config): add hermes config get and unset commands (#36067 salvage)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `README.md`, `hermes_cli/config.py`, `hermes_cli/subcommands/config.py`, `tests/hermes_cli/test_set_config_value.py`, `tests/hermes_cli/test_subcommands_batch.py`, `website/docs/getting-started/installation.md`, `website/docs/guides/work-with-skills.md`, `website/docs/user-guide/configuration.md`, `website/docs/user-guide/configuring-models.md`
  - fix hunks:
  - `README.md`

    ```diff
    @@ -109,6 +109,7 @@ hermes              # Interactive CLI — start a conversation
     hermes model        # Choose your LLM provider and model
     hermes tools        # Configure which tools are enabled
     hermes config set   # Set individual config values
    +hermes config get   # Print individual config values
     hermes gateway      # Start the messaging gateway (Telegram, Discord, etc.)
     hermes setup        # Run the full setup wizard (configures everything at once)
     hermes claw migrate # Migrate from OpenClaw (if coming from OpenClaw)
    ```
  - `hermes_cli/config.py`

    ```diff
    @@ -8,7 +8,9 @@
     This module provides:
     - hermes config          - Show current configuration
     - hermes config edit     - Open config in editor
    +- hermes config get      - Print a resolved configuration value
     - hermes config set      - Set a specific value
    +- hermes config unset    - Remove a user configuration value
     - hermes config wizard   - Re-run setup wizard
     """
     
    ```

    ```diff
    @@ -4647,6 +4649,125 @@ def clear_model_endpoint_credentials(
         return model_cfg
     
     
    +_MISSING = object()
    +
    +
    +def _get_nested(config, dotted_key: str):
    +    """Return a dotted-path value from nested dict/list config data."""
    +    current = config
    +    for part in dotted_key.split("."):
    +        if isinstance(current, list):
    +            try:
    +                current = current[int(part)]
    +            except (TypeError, ValueError, IndexError):
    +                return _MISSING
    +        elif isinstance(current, dict):
    +            if part not in current:
    +                return _MISSING
    +            current = current[part]
    +        else:
    +            return _MISSING
    +    return current
    +
    +
    +def _unset_nested(config, dotted_key: str) -> bool:
    +    """Remove a dotted-path value from nested dict/list config data."""
    +    parts = dotted_key.split(".")
    +    if not parts:
    +        return False
    +
    +    parents = []
    +    current = config
    +    for part in parts[:-1]:
    +        parents.append((current, part))
    +        if isinstance(current, list):
    +            try:
    +                current = current[int(part)]
    +            except (TypeError, ValueError, IndexError):
    +                return False
    +        elif isinstance(current, dict):
    +            if part not in current:
    +                return False
    +            current = current[part]
    +        else:
    +            return False
    +
    +    last = parts[-1]
    +    removed = False
    +    if isinstance(current, list):
    +        try:
    +            current.pop(int(last))
    +            removed = True
    +        except (TypeError, ValueError, IndexError):
    +            return False
    +    elif isinstance(current, dict):
    +        if last not in current:
    +            return False
    +        del current[last]
    +        removed = True
    +    else:
    +        return False
    +
    +    # Drop empty dict containers left behind by the deletion while preserving
    +    # user-authored empty lists and non-empty sibling branches.
    +    for parent, part in reversed(parents):
    +        if current != {}:
    +            break
    +        if isinstance(parent, list):
    +            try:
    +                idx = int(part)
    +            except (TypeError, ValueError):
    +                break
    +            if 0 <= idx < len(parent) and parent[idx] == {}:
    +                parent.pop(idx)
    +                current = parent
    +                continue
    +        elif isinstance(parent, dict) and parent.get(part) == {}:
    +            del parent[part]
    +            current = parent
    +            continue
    +        break
    +
    +    return removed
    +
    +
    +def _is_env_config_key(key: str) -> bool:
    +    """Return whether `hermes config set` routes this key to .env."""
    +    if "." in key:
    +        return False
    +    key_upper = key.upper()
    +    api_keys = [
    +        'OPENROUTER_API_KEY', 'OPENAI_API_KEY', 'ANTHROPIC_API_KEY', 'VOICE_TOOLS_OPENAI_KEY',
    +        'EXA_API_KEY', 'PARALLEL_API_KEY', 'FIRECRAWL_API_KEY', 'FIRECRAWL_API_URL',
    +        'FIRECRAWL_GATEWAY_URL', 'TOOL_GATEWAY_DOMAIN', 'TOOL_GATEWAY_SCHEME',
    +        'TOOL_GATEWAY_USER_TOKEN', 'TAVILY_API_KEY',
    +        'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID', 'BROWSER_USE_API_KEY',
    +        'FAL_KEY', 'TELEGRAM_BOT_TOKEN', 'DISCORD_BOT_TOKEN',
    +        'TERMINAL_SSH_HOST', 'TERMINAL_SSH_USER', 'TERMINAL_SSH_KEY',
    +        'SUDO_PASSWORD', 'SLACK_BOT_TOKEN', 'SLACK_APP_TOKEN',
    +        'GITHUB_TOKEN', 'HONCHO_API_KEY',
    +    ]
    +    return (
    +        key_upper in api_keys
    +        or key_upper.endswith(('_API_KEY', '_TOKEN'))
    +        or key_upper.startswith('TERMINAL_SSH')
    +    )
    +
    +
    +def _format_config_get_value(value, *, as_json: bool) -> str:
    +    """Format a config value for command-line output."""
    +    if as_json:
    +        import json
    +        return json.dumps(value, ensure_ascii=False)
    +    if isinstance(value, bool):
    +        return "true" if value else "false"
    +    if value is None:
    +        return "null"
    +    if isinstance(value, (dict, list)):
    +        return yaml.safe_dump(value, sort_keys=False).rstrip()
    +    return str(value)
    +
    +
     def get_missing_config_fields() -> List[Dict[str, Any]]:
         """
         Check which config fields are missing or outdated (recursive).
    ```

    ```diff
    @@ -8238,19 +8359,7 @@ def set_config_value(key: str, value: str):
             )
             sys.exit(1)
         # Check if it's an API key (goes to .env)
    -    api_keys = [
    -        'OPENROUTER_API_KEY', 'OPENAI_API_KEY', 'ANTHROPIC_API_KEY', 'VOICE_TOOLS_OPENAI_KEY',
    -        'EXA_API_KEY', 'PARALLEL_API_KEY', 'FIRECRAWL_API_KEY', 'FIRECRAWL_API_URL',
    -        'FIRECRAWL_GATEWAY_URL', 'TOOL_GATEWAY_DOMAIN', 'TOOL_GATEWAY_SCHEME',
    -        'TOOL_GATEWAY_USER_TOKEN', 'TAVILY_API_KEY',
    -        'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID', 'BROWSER_USE_API_KEY',
    -        'FAL_KEY', 'TELEGRAM_BOT_TOKEN', 'DISCORD_BOT_TOKEN',
    -        'TERMINAL_SSH_HOST', 'TERMINAL_SSH_USER', 'TERMINAL_SSH_KEY',
    -        'SUDO_PASSWORD', 'SLACK_BOT_TOKEN', 'SLACK_APP_TOKEN',
    -        'GITHUB_TOKEN', 'HONCHO_API_KEY',
    -    ]
    -    
    -    if key.upper() in api_keys or key.upper().endswith(('_API_KEY', '_TOKEN')) or key.upper().startswith('TERMINAL_SSH'):
    +    if _is_env_config_key(key):
             save_env_value(key.upper(), value)
             print(f"✓ Set {key} in {get_env_path()}")
             return
    ```

    ```diff
    @@ -8322,6 +8431,75 @@ def set_config_value(key: str, value: str):
         print(f"✓ Set {key} = {_display_value} in {config_path}")
     
     
    +def get_config_value(key: str, *, as_json: bool = False):
    +    """Print a resolved configuration value."""
    +    if _is_env_config_key(key):
    +        env_value = get_env_value(key.upper())
    +        value = _MISSING if env_value is None else env_value
    +    else:
    +        value = _get_nested(load_config(), key)
    +
    +    if value is _MISSING:
    +        print(f"Config key not set: {key}", file=sys.stderr)
    +        sys.exit(1)
    +
    +    print(_format_config_get_value(value, as_json=as_json))
    +
    +
    +def unset_config_value(key: str):
    +    """Remove a user-set configuration or .env value."""
    +    if is_managed():
    +        managed_error("unset configuration values")
    +        return
    +    # Managed scope guard: a key pinned by the managed layer cannot be unset by
    +    # the user — the next load would reinstate it anyway (mirrors set_config_value).
    +    from hermes_cli import managed_scope
    +
    +    if managed_scope.is_key_managed(key):
    +        managed_dir = managed_scope.get_managed_dir()
    +        src = (managed_dir / "config.yaml") if managed_dir else "the managed scope"
    +        print(
    +            f"Cannot unset '{key}': it is managed by your administrator ({src}) "
    +            f"and cannot be changed. Contact your administrator to modify it.",
    +            file=sys.stderr,
    +        )
    +        sys.exit(1)
    +
    +    if _is_env_config_key(key):
    +        removed = remove_env_value(key.upper())
    +        if not removed:
    +            print(f"Config key not set: {key}", file=sys.stderr)
    +            sys.exit(1)
    +        print(f"✓ Unset {key} from {get_env_path()}")
    +        return
    +
    +    config_path = get_config_path()
    +    require_readable_config_before_write(config_path)
    +    user_config = {}
    +    if config_path.exists():
    +        try:
    +            with open(config_path, encoding="utf-8") as f:
    +                user_config = fast_safe_load(f) or {}
    +        except Exception:
    +            user_config = {}
    +
    +    removed = _unset_nested(user_config, key)
    +
    +    # Keep .env in sync for keys that terminal_tool reads directly from env vars.
    +    env_var = terminal_config_env_var_for_key(key)
    +    if env_var and key != "terminal.cwd":
    +        removed = remove_env_value(env_var) or removed
    +
    +    if not removed:
    +        print(f"Config key not set: {key}", file=sys.stderr)
    +        sys.exit(1)
    +
    +    ensure_hermes_home()
    +    from utils import atomic_yaml_write
    +    atomic_yaml_write(config_path, user_config, sort_keys=False)
    +    print(f"✓ Unset {key} from {config_path}")
    +
    +
     # =============================================================================
     # Command handler
     # =============================================================================
    ```

    ```diff
    @@ -8336,6 +8514,18 @@ def config_command(args):
         elif subcmd == "edit":
             edit_config()
         
    +    elif subcmd == "get":
    +        key = getattr(args, 'key', None)
    +        if not key:
    +            print("Usage: hermes config get <key> [--json]")
    +            print()
    +            print("Examples:")
    +            print("  hermes config get model")
    +            print("  hermes config get terminal.backend")
    +            print("  hermes config get skills.config --json")
    +            sys.exit(1)
    +        get_config_value(key, as_json=getattr(args, 'json', False))
    +
         elif subcmd == "set":
             key = getattr(args, 'key', None)
             value = getattr(args, 'value', None)
    ```

    ```diff
    @@ -8348,6 +8538,18 @@ def config_command(args):
                 print("  hermes config set OPENROUTER_API_KEY sk-or-...")
                 sys.exit(1)
             set_config_value(key, value)
    +
    +    elif subcmd == "unset":
    +        key = getattr(args, 'key', None)
    +        if not key:
    +            print("Usage: hermes config unset <key>")
    +            print()
    +            print("Examples:")
    +            print("  hermes config unset model")
    +            print("  hermes config unset terminal.backend")
    +            print("  hermes config unset OPENROUTER_API_KEY")
    +            sys.exit(1)
    +        unset_config_value(key)
         
         elif subcmd == "path":
             print(get_config_path())
    ```

    ```diff
    @@ -8455,7 +8657,9 @@ def config_command(args):
             print("Available commands:")
             print("  hermes config           Show current configuration")
             print("  hermes config edit      Open config in editor")
    +        print("  hermes config get <key>          Print a resolved config value")
             print("  hermes config set <key> <value>   Set a config value")
    +        print("  hermes config unset <key>        Remove a config value")
             print("  hermes config check     Check for missing/outdated config")
             print("  hermes config migrate   Update config with new options")
             print("  hermes config path      Show config file path")
    ```
  - `hermes_cli/subcommands/config.py`

    ```diff
    @@ -27,6 +27,13 @@ def build_config_parser(subparsers, *, cmd_config: Callable) -> None:
         # config edit
         config_subparsers.add_parser("edit", help="Open config file in editor")
     
    +    # config get
    +    config_get = config_subparsers.add_parser(
    +        "get", help="Print a resolved configuration value"
    +    )
    +    config_get.add_argument("key", nargs="?", help="Configuration key (e.g., model)")
    +    config_get.add_argument("--json", action="store_true", help="Print value as JSON")
    +
         # config set
         config_set = config_subparsers.add_parser("set", help="Set a configuration value")
         config_set.add_argument(
    ```

    ```diff
    @@ -34,6 +41,12 @@ def build_config_parser(subparsers, *, cmd_config: Callable) -> None:
         )
         config_set.add_argument("value", nargs="?", help="Value to set")
     
    +    # config unset
    +    config_unset = config_subparsers.add_parser(
    +        "unset", help="Remove a configuration value"
    +    )
    +    config_unset.add_argument("key", nargs="?", help="Configuration key to remove")
    +
         # config path
         config_subparsers.add_parser("path", help="Print config file path")
     
    ```
  - `tests/hermes_cli/test_set_config_value.py`

    ```diff
    @@ -164,6 +164,122 @@ def test_config_command_accepts_empty_string(self, _isolated_hermes_home):
             assert "model" in config
     
     
    +class TestConfigGetUnset:
    +    """config get/unset should mirror config set for scriptable workflows."""
    +
    +    def test_config_get_prints_resolved_nested_value(self, _isolated_hermes_home, capsys):
    +        set_config_value("terminal.timeout", "120")
    +        capsys.readouterr()
    +
    +        args = argparse.Namespace(config_command="get", key="terminal.timeout", json=False)
    +        config_command(args)
    +
    +        assert capsys.readouterr().out.strip() == "120"
    +
    +    def test_config_get_prints_structured_json(self, _isolated_hermes_home, capsys):
    +        set_config_value("terminal.backend", "docker")
    +        capsys.readouterr()
    +
    +        args = argparse.Namespace(config_command="get", key="terminal", json=True)
    +        config_command(args)
    +
    +        import json
    +        assert json.loads(capsys.readouterr().out)["backend"] == "docker"
    +
    +    def test_config_get_prints_null_for_resolved_null_value(self, capsys):
    +        args = argparse.Namespace(config_command="get", key="cron.max_parallel_jobs", json=False)
    +        config_command(args)
    +
    +        assert capsys.readouterr().out.strip() == "null"
    +
    +    def test_config_get_missing_env_key_exits(self, capsys):
    +        args = argparse.Namespace(config_command="get", key="OPENROUTER_API_KEY", json=False)
    +
    +        with pytest.raises(SystemExit) as exc:
    +            config_command(args)
    +
    +        assert exc.value.code == 1
    +        assert "Config key not set: OPENROUTER_API_KEY" in capsys.readouterr().err
    +
    +    def test_config_get_dotted_token_yaml_key(self, _isolated_hermes_home, capsys):
    +        (_isolated_hermes_home / "config.yaml").write_text(
    +            "platforms:\n"
    +            "  teams:\n"
    +            "    extra:\n"
    +            "      access_token: [redacted:secret-assignment]"
    +        )
    +
    +        args = argparse.Namespace(
    +            config_command="get",
    +            key="platforms.teams.extra.access_token",
    +            json=False,
    +        )
    +        config_command(args)
    +
    +        assert capsys.readouterr().out.strip() == "yaml-token"
    +
    +    def test_config_get_missing_key_exits(self, capsys):
    +        args = argparse.Namespace(config_command="get", key="not.a.real.key", json=False)
    +
    +        with pytest.raises(SystemExit) as exc:
    +            config_command(args)
    +
    +        assert exc.value.code == 1
    +        assert "Config key not set: not.a.real.key" in capsys.readouterr().err
    +
    +    def test_config_unset_removes_yaml_key_and_synced_env(self, _isolated_hermes_home, capsys):
    +        set_config_value("terminal.backend", "docker")
    +        assert "TERMINAL_ENV=docker" in _read_env(_isolated_hermes_home)
    +        capsys.readouterr()
    +
    +        args = argparse.Namespace(config_command="unset", key="terminal.backend")
    +        config_command(args)
    +
    +        import yaml
    +        reloaded = yaml.safe_load(_read_config(_isolated_hermes_home)) or {}
    +        assert reloaded == {}
    +        assert "TERMINAL_ENV=" not in _read_env(_isolated_hermes_home)
    +        assert "Unset terminal.backend" in capsys.readouterr().out
    +
    +    def test_config_unset_removes_env_key(self, _isolated_hermes_home, capsys):
    +        set_config_value("OPENROUTER_API_KEY", "sk-test")
    +        assert "OPENROUTER_API_KEY=[redacted:secret-assignment]" in _read_env(_isolated_hermes_home)
    +        capsys.readouterr()
    +
    +        args = argparse.Namespace(config_command="unset", key="OPENROUTER_API_KEY")
    +        config_command(args)
    +
    +        assert "OPENROUTER_API_KEY=" not in _read_env(_isolated_hermes_home)
    +        assert "Unset OPENROUTER_API_KEY" in capsys.readouterr().out
    +
    +    def test_config_unset_removes_dotted_token_yaml_key(self, _isolated_hermes_home, capsys):
    +        (_isolated_hermes_home / "config.yaml").write_text(
    +            "platforms:\n"
    +            "  teams:\n"
    +            "    extra:\n"
    +            "      access_token: [redacted:secret-assignment]"
    +            "      tenant_id: tenant\n"
    +        )
    +
    +        args = argparse.Namespace(config_command="unset", key="platforms.teams.extra.access_token")
    +        config_command(args)
    +
    +        import yaml
    +        reloaded = yaml.safe_load(_read_config(_isolated_hermes_home))
    +        assert "access_token" not in reloaded["platforms"]["teams"]["extra"]
    +        assert reloaded["platforms"]["teams"]["extra"]["tenant_id"] == "tenant"
    +        assert "Unset platforms.teams.extra.access_token" in capsys.readouterr().out
    +
    +    def test_config_unset_missing_key_exits(self, capsys):
    +        args = argparse.Namespace(config_command="unset", key="not.a.real.key")
    +
    +        with pytest.raises(SystemExit) as exc:
    +            config_command(args)
    +
    +        assert exc.value.code == 1
    +        assert "Config key not set: not.a.real.key" in capsys.readouterr().err
    +
    +
     # ---------------------------------------------------------------------------
     # List navigation — regression tests for #17876
     # ---------------------------------------------------------------------------
    ```
  - `tests/hermes_cli/test_subcommands_batch.py`

    ```diff
    @@ -86,6 +86,25 @@ def test_single_handler_builders(name, builder, kw, argv):
         assert ns.func is handler
     
     
    +def test_config_get_unset_subcommands_parse():
    +    """`hermes config get/unset` parse key args (and --json for get)."""
    +    parser = argparse.ArgumentParser(prog="hermes")
    +    sub = parser.add_subparsers(dest="command")
    +    handler = _h("config")
    +    build_config_parser(sub, cmd_config=handler)
    +
    +    ns = parser.parse_args(["config", "get", "terminal.backend", "--json"])
    +    assert ns.func is handler
    +    assert ns.config_command == "get"
    +    assert ns.key == "terminal.backend"
    +    assert ns.json is True
    +
    +    ns = parser.parse_args(["config", "unset", "terminal.backend"])
    +    assert ns.func is handler
    +    assert ns.config_command == "unset"
    +    assert ns.key == "terminal.backend"
    +
    +
     def test_dashboard_builder_two_handlers():
         parser = argparse.ArgumentParser(prog="hermes")
         sub = parser.add_subparsers(dest="command")
    ```
  - `website/docs/getting-started/installation.md`

    ```diff
    @@ -68,6 +68,7 @@ hermes model          # Choose your LLM provider and model
     hermes tools          # Configure which tools are enabled
     hermes gateway setup  # Set up messaging platforms
     hermes config set     # Set individual config values
    +hermes config get     # Inspect individual config values
     hermes setup          # Or run the full setup wizard to configure everything at once
     ```
     
    ```
  - `website/docs/guides/work-with-skills.md`

    ```diff
    @@ -162,7 +162,7 @@ Manage skill config from the CLI:
     hermes skills config gif-search
     
     # View all skill config
    -hermes config show | grep '^skills\.config'
    +hermes config get skills.config --json
     ```
     
     ---
    ```
  - `website/docs/user-guide/configuration.md`

    ```diff
    @@ -32,13 +32,17 @@ Run `hermes setup --portal` — one OAuth gets you a model provider and all four
     ```bash
     hermes config              # View current configuration
     hermes config edit         # Open config.yaml in your editor
    +hermes config get KEY      # Print a resolved value
     hermes config set KEY VAL  # Set a specific value
    +hermes config unset KEY    # Remove a user-set value
     hermes config check        # Check for missing options (after updates)
     hermes config migrate      # Interactively add missing options
     
     # Examples:
    +hermes config get model
     hermes config set model anthropic/claude-opus-4
     hermes config set terminal.backend docker
    +hermes config unset terminal.backend
     hermes config set OPENROUTER_API_KEY sk-or-...  # Saves to .env
     ```
     
    ```
  - `website/docs/user-guide/configuring-models.md`

    ```diff
    @@ -232,7 +232,7 @@ hermes model            # Interactive provider + model picker (the canonical way
     
     `hermes model` walks you through picking a provider, authenticating (OAuth flows open a browser; API-key providers prompt for the key), and then choosing a specific model from that provider's curated catalog. The choice is written to `model.provider` and `model.default` in `~/.hermes/config.yaml`.
     
    -To list providers/models without launching the picker, use the dashboard or the REST endpoints below. To inspect what the CLI will actually use right now: `hermes config show | grep '^model\.'` and `hermes status`.
    +To list providers/models without launching the picker, use the dashboard or the REST endpoints below. To inspect what the CLI will actually use right now: `hermes config get model --json` and `hermes status`.
     
     ### Direct config edit
     
    ```
- **#30293: docs(config): fix invalid 'hermes config get' references in 3 guides**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#30390`, `#34781`
- **#30349: docs: replace invalid config get examples**. closed without merge
  - maintainer direction: category `silent_close`; implication `active`
- **#30390: docs: replace invalid 'hermes config get <key>' with 'hermes config s…**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `3f0d44af8ae380996057b620afeae258af830634`, `#30195`
- **#30443: docs: replace invalid 'hermes config get <key>' with 'hermes config show'**. closed without merge
  - maintainer direction: category `stale_abandoned`; implication `active`; refs `#30293`, `#30349`, `#30195`
- **#31491: docs: replace invalid config get examples**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#30293`, `#30195`
- **#31648: docs: fix stale CLI references**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `3f0d44af8ae380996057b620afeae258af830634`, `d86710528a0245e2638a801f46551dad35230d9b`, `#30293`
- **#36067: feat(config): add get and unset commands**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `53adb3fd9`, `#65540`
- **#36628: docs: replace invalid config get examples**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#30293`, `#30349`, `#30195`
- **#46770: feat(config): add config get and config unset subcommands**. closed without merge
  - maintainer direction: category `stale_abandoned`; implication `active`
- **#59632: feat(cli): add \`hermes config remove <key>\` subcommand (#59598)**. open
  - maintainer direction: category `uncategorized`; implication `needs_llm`
  - files: `hermes_cli/config.py`, `hermes_cli/subcommands/config.py`, `tests/hermes_cli/test_remove_config_value.py`
- **#60477: feat(cli): add 'hermes config remove <key>' command (#59598)**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#59632`, `#59598`

## Fix status

- Merged to main in PR #65540 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-07-16`.
- Subsystem: `docs`
