hermes-agent/tests/tools
Teknium 243a01d5d7 fix(curator): make the autonomous write policy consistent (#67140)
The background write guard decided ownership from `isinstance(usage_rec, dict)`,
so a local skill with NO usage record passed. That successful write called
bump_patch(), which created a `created_by: null` record — and the identical
write was refused from then on. "Allowed exactly once, then never" is a race
with our own bookkeeping, not a policy. Reproduced on main: patch #1 succeeds,
patch #2 with the same arguments is refused.

Option B from the issue. Option A (split `session_review` from
`scheduled_curator` and let the session fork patch user-owned skills it
consulted) would widen autonomous write permission onto skills the user owns
with no user present to consent — wrong direction for a no-user-present actor.

- skill_manager_tool: missing and explicit-null records now resolve
  IDENTICALLY, both fail closed. The refusal names the reason and points at
  `hermes curator adopt <name>`.
- background_review: both review prompts told the reviewer to patch any skill
  consulted in the session and claimed pinned skills could be improved, while
  enforcement refused both. Prompts now list pinned, external, and user-owned
  skills as protected, and tell the reviewer to RECOMMEND adoption instead of
  attempting a write that will be refused.
- skill_usage: document that `created_by` is a curator-management policy flag,
  not a provenance claim, and add `is_curator_managed()` so call sites read as
  the question they ask. Field name retained — it is on disk in every
  `.usage.json` and renaming would strand those records.
- curator CLI: `hermes curator list-unmanaged` itemizes unmanaged skills with
  the reason each is unmanaged (completes the #67139 spec).

Foreground writes are untouched: a user-directed edit to a user-owned skill
still works, including on pinned skills.

Sibling tests: 9 failures in test_skill_manager_tool.py were fixtures that
created record-less skills to exercise OTHER guards (consolidation-delete,
read-before-write) and relied on ownership falling through. Fixed at the
fixture, since the real curator only ever operates on managed sediment. One
test asserted the old "manually authored" wording; rewritten to assert the
behavior contract instead of the string.

Validation: 274 targeted tests + all 7 background-review files (60 tests) pass.
E2E on a temp HERMES_HOME (30 checks) covers the flip, foreground writes,
adoption unblocking, pin semantics, prompt/enforcement parity, and the new verb.
Each new test sabotage-verified: revert the fix, confirm it goes red.

Fixes #67140
2026-07-25 19:27:17 -07:00
..
__init__.py
…
conftest.py
…
test_accretion_caps.py
…
test_ansi_strip.py
…
test_approval.py
…
test_approval_deny_rules.py
…
test_approval_heartbeat.py
…
test_approval_interrupt.py
…
test_approval_plugin_hooks.py
…
test_approved_command_clean_slate.py
…
test_async_delegation.py fix(delegation): persist origin_session_id in durable dispatch records 2026-07-23 11:55:17 -07:00
test_async_delegation_fd_leak.py fix(gateway,tools,agent): close leaked SQLite connections in delivery, delegation, and verification ledgers 2026-07-24 15:55:08 -07:00
test_base_environment.py fix(terminal): stop shared bash snapshot leaking HERMES_SESSION_* across sessions 2026-07-24 23:09:02 -07:00
test_blueprints.py
…
test_browser_camofox.py
…
test_browser_camofox_auth.py
…
test_browser_camofox_ensure_tab.py
…
test_browser_camofox_persistence.py
…
test_browser_camofox_private_page_guard.py
…
test_browser_camofox_state.py
…
test_browser_camofox_timeout.py
…
test_browser_cdp_override.py
…
test_browser_cdp_tool.py
…
test_browser_chromium_autoinstall.py
…
test_browser_chromium_check.py
…
test_browser_cleanup.py
…
test_browser_cloud_fallback.py
…
test_browser_cloud_provider_cache.py
…
test_browser_command_timeout_race.py
…
test_browser_console.py fix(skills): move dogfood skill into the software-development category 2026-07-23 19:45:54 -07:00
test_browser_console_ssrf.py
…
test_browser_content_none_guard.py
…
test_browser_eval_ssrf.py
…
test_browser_eval_supervisor_path.py
…
test_browser_get_images_ssrf.py
…
test_browser_hardening.py
…
test_browser_headed_mode.py
…
test_browser_homebrew_paths.py
…
test_browser_hybrid_routing.py
…
test_browser_lightpanda.py
…
test_browser_open_timeout.py
…
test_browser_orphan_reaper.py
…
test_browser_private_page_action_guard.py
…
test_browser_secret_exfil.py
…
test_browser_snapshot_ssrf.py
…
test_browser_ssrf_local.py
…
test_browser_supervisor.py
…
test_browser_supervisor_healthcheck.py
…
test_browser_type_redaction.py
…
test_budget_config.py
…
test_checkpoint_manager.py fix(checkpoints): require positive volume-attachment evidence before orphan classification 2026-07-24 19:10:34 -07:00
test_clarify_gateway.py fix(clarify): one canonical timeout across CLI, TUI/desktop, and gateway (#69774) 2026-07-22 23:25:13 -05:00
test_clarify_tool.py
…
test_clipboard.py
…
test_code_execution.py
…
test_code_execution_modes.py
…
test_code_execution_windows_env.py
…
test_command_guards.py
…
test_computer_use.py fix(computer-use): handle Linux cua window metadata 2026-07-23 08:11:58 -07:00
test_computer_use_capture_routing.py
…
test_computer_use_cua_backend_linux.py fix(computer-use): handle Linux cua window metadata 2026-07-23 08:11:58 -07:00
test_computer_use_delivery_ladder.py
…
test_computer_use_null_pid_windows.py
…
test_computer_use_vision_routing.py
…
test_config_null_guard.py
…
test_container_cwd_sanitize.py
…
test_credential_files.py
…
test_credential_pool_env_fallback.py
…
test_cron_approval_mode.py
…
test_cron_prompt_injection.py
…
test_cronjob_run_immediate.py fix(cron): reconcile external provider after a claimed direct run (#70479) 2026-07-24 13:37:04 +10:00
test_cronjob_tools.py
…
test_cross_profile_guard.py
…
test_daemon_pool.py
…
test_daytona_environment.py
…
test_debug_helpers.py
…
test_delegate.py
…
test_delegate_apiserver_background.py fix(gateway): deliver kanban/delegate wake-ups to api_server sessions 2026-07-23 11:55:17 -07:00
test_delegate_composite_toolsets.py
…
test_delegate_kanban_isolation.py test: pin repo root on PYTHONPATH for subprocess-boundary kanban isolation tests 2026-07-23 07:33:36 -07:00
test_delegate_subagent_timeout_diagnostic.py
…
test_delegate_summary_budget.py
…
test_delegate_toolset_scope.py
…
test_delegation_live_log.py
…
test_desktop_ui.py feat(desktop): agent can focus panes + shared desktop-UI event bridge 2026-07-22 12:13:01 -05:00
test_discord_send_message_caption.py
…
test_discord_tool.py
…
test_docker_cgroup_limits.py
…
test_docker_config_migrate.py
…
test_docker_environment.py fix: repair sweep fallout — duplicate encoding kwargs, non-subprocess call sites, kwarg-snapshot tests 2026-07-24 11:45:57 -07:00
test_docker_find.py
…
test_docker_network_config.py test(docker): update network-reuse harness fake ps output for egress-aware 3-field probe 2026-07-24 09:49:00 -07:00
test_docker_orphan_reaper_integration.py
…
test_docker_rebootstrap_nous_session.py
…
test_dockerfile_immutable_install.py
…
test_dockerfile_node_modules_perms.py
…
test_dockerfile_pid1_reaping.py
…
test_env_passthrough.py
…
test_env_probe.py
…
test_execute_code_approval_cluster.py fix(kanban): harden delegated-child mutation boundary 2026-07-23 07:33:36 -07:00
test_execution_flag_detection.py
…
test_feishu_tools.py
…
test_file_operations.py
…
test_file_operations_edge_cases.py
…
test_file_ops_cwd_tracking.py
…
test_file_read_guards.py
…
test_file_staleness.py
…
test_file_state_registry.py
…
test_file_sync.py
…
test_file_sync_back.py
…
test_file_sync_perf.py
…
test_file_sync_sigint.py
…
test_file_tools.py
…
test_file_tools_container_config.py
…
test_file_tools_cwd_resolution.py
…
test_file_tools_live.py
…
test_file_tools_tilde_profile.py
…
test_file_write_safety.py
…
test_find_shell.py
…
test_focus_pane_tool.py feat(desktop): agent can focus panes + shared desktop-UI event bridge 2026-07-22 12:13:01 -05:00
test_force_dangerous_override.py
…
test_fuzzy_match.py
…
test_gateway_cwd_contract.py
…
test_gnu_long_option_abbreviation_bypass.py
…
test_hardline_blocklist.py
…
test_heartbeat_stale_thresholds.py
…
test_hermes_subprocess_env.py fix(kanban): harden delegated-child mutation boundary 2026-07-23 07:33:36 -07:00
test_hidden_dir_filter.py
…
test_homeassistant_tool.py
…
test_hook_output_spill.py
…
test_hub_lock_non_utf8_68053.py fix(skills): tolerate non-UTF-8 bytes in hub lock.json 2026-07-24 17:10:39 -07:00
test_image_generation.py
…
test_image_generation_artifacts.py
…
test_image_generation_env.py
…
test_image_generation_image_to_image.py
…
test_image_generation_plugin_dispatch.py
…
test_image_source.py
…
test_init_session_cwd_respect.py
…
test_interrupt.py
…
test_kanban_redaction.py
…
test_kanban_tools.py fix(kanban): preserve cross-profile project child routing 2026-07-23 08:34:06 -07:00
test_lazy_deps.py
…
test_lazy_deps_durable_target.py
…
test_line_ending_preservation.py
…
test_llm_content_none_guard.py
…
test_local_background_child_hang.py
…
test_local_cwd_permission_fallback.py
…
test_local_env_blocklist.py
…
test_local_env_cwd_recovery.py
…
test_local_env_relative_cwd.py
…
test_local_env_session_leak.py
…
test_local_env_windows_msys.py
…
test_local_interrupt_cleanup.py
…
test_local_shell_init.py fix: brace-group the filtered export dump so $BASHPID expands in the parent shell 2026-07-24 23:09:02 -07:00
test_local_tempdir.py
…
test_managed_browserbase_and_modal.py
…
test_managed_media_gateways.py
…
test_managed_modal_environment.py
…
test_managed_tool_gateway.py
…
test_mcp_bridge_single_failure.py
…
test_mcp_cancelled_error_propagation.py
…
test_mcp_capability_gating.py
…
test_mcp_circuit_breaker.py
…
test_mcp_client_cert.py
…
test_mcp_dashboard_oauth.py
…
test_mcp_dynamic_discovery.py
…
test_mcp_elicitation.py
…
test_mcp_empty_error_message.py
…
test_mcp_failure_classification.py
…
test_mcp_image_content.py
…
test_mcp_invalid_url.py
…
test_mcp_list_pagination.py
…
test_mcp_loop_profile_override.py
…
test_mcp_oauth.py
…
test_mcp_oauth_bidirectional.py
…
test_mcp_oauth_cold_load_expiry.py
…
test_mcp_oauth_integration.py
…
test_mcp_oauth_manager.py
…
test_mcp_oauth_metadata.py
…
test_mcp_parked_self_probe.py
…
test_mcp_poll_loop_oom_integration.py
…
test_mcp_preflight_content_type.py
…
test_mcp_probe.py
…
test_mcp_rapid_drop_budget.py
…
test_mcp_reconnect_log_hygiene.py
…
test_mcp_reconnect_retry_reset.py
…
test_mcp_reconnect_signal.py
…
test_mcp_register_wakes_stale.py
…
test_mcp_resource_content.py
…
test_mcp_server_log_notifications.py
…
test_mcp_sse_transport.py
…
test_mcp_stability.py
…
test_mcp_stdio_encoding_handler.py fix(mcp): use encoding_error_handler='replace' for stdio transport 2026-07-24 15:47:12 -07:00
test_mcp_stdio_init_timeout.py
…
test_mcp_stdio_watchdog.py
…
test_mcp_structured_content.py
…
test_mcp_tool.py
…
test_mcp_tool_401_handling.py
…
test_mcp_tool_issue_948.py
…
test_mcp_tool_session_expired.py
…
test_mcp_transport_group_reconnect.py
…
test_mcp_utility_capability_gating.py
…
test_media_caption_split.py
…
test_memory_tool.py fix(memory): close second-read drift race and treat invalid UTF-8 as unreadable 2026-07-24 15:58:01 -07:00
test_memory_tool_import_fallback.py
…
test_memory_tool_schema.py
…
test_microsoft_graph_auth.py
…
test_microsoft_graph_client.py
…
test_modal_bulk_upload.py
…
test_modal_sandbox_fixes.py
…
test_modal_snapshot_isolation.py
…
test_notify_on_complete.py
…
test_open_preview_tool.py feat(desktop): agent can focus panes + shared desktop-UI event bridge 2026-07-22 12:13:01 -05:00
test_osv_check.py
…
test_parse_env_var.py
…
test_patch_failure_tracking.py
…
test_patch_parser.py
…
test_pr_6656_regressions.py
…
test_process_registry.py fix(process_registry): reader loop no longer hangs when an orphaned grandchild holds the stdout pipe 2026-07-24 15:59:02 -07:00
test_read_extract.py
…
test_read_loop_detection.py
…
test_refresh_agent_mcp_tools.py fix(memory): honor disabled toolsets for provider tools 2026-07-24 13:00:53 +05:30
test_registry.py
…
test_request_tool_approval.py
…
test_resolve_path.py
…
test_restored_delegation_ownership.py
…
test_schema_sanitizer.py
…
test_search_budget_truncation.py
…
test_search_error_guard.py
…
test_search_hidden_dirs.py
…
test_send_message_missing_platforms.py
…
test_send_message_react.py
…
test_send_message_slack.py fix(slack): prefer live send adapter and try multi-workspace tokens individually 2026-07-23 12:01:24 -07:00
test_send_message_target_parse.py
…
test_send_message_telegram_proxy.py
…
test_send_message_tool.py fix(slack): unify DM-resolution caches and bound wave-2 caches (C16 policy) 2026-07-22 21:58:13 -07:00
test_session_cwd_store.py
…
test_session_search.py feat(session-search): give the agent a link to hand back 2026-07-24 23:30:25 -05:00
test_shared_container_task_id.py
…
test_shell_bypass_denylist.py
…
test_signal_media.py
…
test_singularity_preflight.py
…
test_skill_bundle_provenance.py fix(security): guard remaining preflighted HTTP fetches 2026-07-23 11:44:43 -07:00
test_skill_env_passthrough.py
…
test_skill_improvements.py
…
test_skill_manager_tool.py fix(curator): make the autonomous write policy consistent (#67140) 2026-07-25 19:27:17 -07:00
test_skill_provenance.py
…
test_skill_size_limits.py
…
test_skill_usage.py feat(curator): surface unmanaged skills and add `curator adopt` 2026-07-25 18:10:24 -07:00
test_skill_view_path_check.py
…
test_skill_view_traversal.py
…
test_skills_ast_audit.py
…
test_skills_guard.py
…
test_skills_hub.py fix(security): pin DNS resolutions for SSRF-safe fetches 2026-07-23 11:44:43 -07:00
test_skills_hub_browse_sh.py
…
test_skills_hub_clawhub.py fix(security): pin DNS resolutions for SSRF-safe fetches 2026-07-23 11:44:43 -07:00
test_skills_list_modified_diff.py
…
test_skills_sync.py feat(curator): surface unmanaged skills and add `curator adopt` 2026-07-25 18:10:24 -07:00
test_skills_tool.py
…
test_skills_tool_discovery_cache.py
…
test_skills_tool_profile_scope.py
…
test_slack_send_message_media.py test(slack): cover send_message MEDIA delivery 2026-07-22 21:58:13 -07:00
test_slash_confirm.py
…
test_smart_approval_injection.py
…
test_snapshot_session_id_leak.py fix: brace-group the filtered export dump so $BASHPID expands in the parent shell 2026-07-24 23:09:02 -07:00
test_spotify_client.py
…
test_ssh_bulk_upload.py
…
test_ssh_environment.py
…
test_stage2_hook_seed_one_symlinks.py
…
test_stage2_hook_symlink_chown.py
…
test_subprocess_stdin_guard.py
…
test_subprocess_utf8_encoding.py fix: extend UTF-8 encoding to _op_version probe (#53428) 2026-07-24 11:45:57 -07:00
test_symlink_prefix_confusion.py
…
test_sync_back_backends.py
…
test_telegram_send_message_caption.py
…
test_terminal_compound_background.py
…
test_terminal_config_env_sync.py
…
test_terminal_env_bridge.py
…
test_terminal_exit_semantics.py
…
test_terminal_foreground_timeout_cap.py
…
test_terminal_none_command_guard.py
…
test_terminal_output_transform_hook.py
…
test_terminal_requirements.py
…
test_terminal_task_cwd.py
…
test_terminal_timeout_output.py
…
test_terminal_tool.py
…
test_terminal_tool_pty_fallback.py
…
test_terminal_tool_requirements.py
…
test_threaded_process_handle.py
…
test_threat_patterns.py
…
test_tirith_security.py
…
test_todo_tool.py
…
test_todo_tool_type_coercion.py
…
test_tool_backend_helpers.py
…
test_tool_output_limits.py
…
test_tool_result_storage.py
…
test_tool_search.py
…
test_tool_search_context_provider.py
…
test_transcription.py
…
test_transcription_command_providers.py
…
test_transcription_deepinfra.py
…
test_transcription_dotenv_fallback.py
…
test_transcription_plugin_dispatch.py
…
test_transcription_tools.py fix(stt): flag empty transcripts as no_speech 2026-07-22 17:47:04 -05:00
test_tts_command_providers.py
…
test_tts_deepinfra.py
…
test_tts_dotenv_fallback.py
…
test_tts_gemini.py
…
test_tts_kittentts.py
…
test_tts_max_text_length.py
…
test_tts_mistral.py
…
test_tts_opus_routing.py
…
test_tts_path_traversal.py
…
test_tts_piper.py
…
test_tts_plugin_dispatch.py
…
test_tts_speed.py
…
test_tts_streaming.py feat(voice): speech-interrupted latch in the TTS streaming core 2026-07-22 17:53:06 -05:00
test_tts_xai_speech_tags.py
…
test_url_safety.py fix(url_safety): harden proxy DNS delegation — literal IPs stay fail-closed + regression tests 2026-07-24 10:37:29 -07:00
test_video_analyze.py
…
test_video_generation_dispatch.py
…
test_video_generation_dynamic_schema.py
…
test_video_generation_tool_surface_matrix.py
…
test_vision_native_fast_path.py
…
test_vision_tools.py
…
test_voice_cli_integration.py feat(voice): stream any provider in the CLI, with barge-in capture 2026-07-22 17:47:15 -05:00
test_voice_mode.py fix(kanban): harden delegated-child mutation boundary 2026-07-23 07:33:36 -07:00
test_watch_patterns.py
…
test_web_extract_robustness.py
…
test_web_providers.py
…
test_web_providers_brave_free.py
…
test_web_providers_ddgs.py
…
test_web_providers_searxng.py
…
test_web_providers_xai.py
…
test_web_tools_config.py
…
test_web_tools_dict_urls.py
…
test_web_tools_tavily.py
…
test_web_tools_truncate.py
…
test_website_policy.py
…
test_whatsapp_send_message_media.py
…
test_windows_compat.py
…
test_windows_native_support.py fix(gateway): retry detached restart watcher without breakaway 2026-07-23 17:59:47 -07:00
test_write_approval.py
…
test_write_deny.py
…
test_write_file_syntax_gate.py
…
test_x_search_tool.py docs(xai): clarify x_search vs xurl routing without schema cross-refs 2026-07-23 21:06:47 -07:00
test_xai_http_storage.py
…
test_yolo_mode.py
…
test_zombie_process_cleanup.py
…