config

Bot configuration loaded from config.yaml with environment variable overrides.

Supports a platforms list so multiple chat platforms (Matrix, Discord, …) can be configured independently alongside the shared LLM / web settings.

class config.RedisSSLConfig(**data)[source]

Bases: BaseModel

Parameters:
  • enabled (bool)

  • host (str)

  • port (int)

  • ssl_certfile (str)

  • ssl_keyfile (str)

  • ssl_ca_certs (str)

  • ssl_cert_reqs (Literal['required', 'none'])

enabled: bool
host: str
port: int
ssl_certfile: str
ssl_keyfile: str
ssl_ca_certs: str
ssl_cert_reqs: Literal['required', 'none']
classmethod validate_paths_exist(v)[source]

Validate that a Redis mTLS credential path points at a real file.

Pydantic field validator wired to the ssl_certfile, ssl_keyfile, and ssl_ca_certs fields of RedisSSLConfig. It wraps the supplied path in pathlib.Path and rejects the value unless that path resolves to an existing regular file, so a missing client certificate, private key, or CA root is caught at config-load time rather than surfacing later as an opaque TLS handshake failure when the Redis client connects.

Pydantic invokes this automatically during model construction; there are no direct internal callers. It performs a single filesystem stat (via Path.is_file()) and touches no Redis/KG/LLM/HTTP collaborator.

Parameters:

v (str) – The candidate filesystem path for a cryptographic credential, as provided in YAML or the environment.

Returns:

The same path v, unchanged, when it names an existing file.

Return type:

str

Raises:

ValueError – If v does not point at an existing regular file; pydantic surfaces this as a validation error.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class config.BotSettings(_case_sensitive=None, _nested_model_default_partial_update=None, _env_prefix=None, _env_prefix_target=None, _env_file=PosixPath('.'), _env_file_encoding=None, _env_ignore_empty=None, _env_nested_delimiter=None, _env_nested_max_split=None, _env_parse_none_str=None, _env_parse_enums=None, _cli_prog_name=None, _cli_parse_args=None, _cli_settings_source=None, _cli_parse_none_str=None, _cli_hide_none_type=None, _cli_avoid_json=None, _cli_enforce_required=None, _cli_use_class_docs_for_groups=None, _cli_exit_on_error=None, _cli_prefix=None, _cli_flag_prefix_char=None, _cli_implicit_flags=None, _cli_ignore_unknown_args=None, _cli_kebab_case=None, _cli_shortcuts=None, _secrets_dir=None, _build_sources=None, **values)[source]

Bases: BaseSettings

Parameters:
  • _case_sensitive (bool | None)

  • _nested_model_default_partial_update (bool | None)

  • _env_prefix (str | None)

  • _env_prefix_target (EnvPrefixTarget | None)

  • _env_file (DotenvType | None)

  • _env_file_encoding (str | None)

  • _env_ignore_empty (bool | None)

  • _env_nested_delimiter (str | None)

  • _env_nested_max_split (int | None)

  • _env_parse_none_str (str | None)

  • _env_parse_enums (bool | None)

  • _cli_prog_name (str | None)

  • _cli_parse_args (bool | list[str] | tuple[str, ...] | None)

  • _cli_settings_source (CliSettingsSource[Any] | None)

  • _cli_parse_none_str (str | None)

  • _cli_hide_none_type (bool | None)

  • _cli_avoid_json (bool | None)

  • _cli_enforce_required (bool | None)

  • _cli_use_class_docs_for_groups (bool | None)

  • _cli_exit_on_error (bool | None)

  • _cli_prefix (str | None)

  • _cli_flag_prefix_char (str | None)

  • _cli_implicit_flags (bool | Literal['dual', 'toggle'] | None)

  • _cli_ignore_unknown_args (bool | None)

  • _cli_kebab_case (bool | Literal['all', 'no_enums'] | None)

  • _cli_shortcuts (Mapping[str, str | list[str]] | None)

  • _secrets_dir (PathType | None)

  • _build_sources (tuple[tuple[PydanticBaseSettingsSource, ...], dict[str, Any]] | None)

  • bot_token (str)

  • admin_user_ids (list[str])

  • dangerous_command_warning_enabled (bool)

  • dangerous_command_similarity_threshold (float)

  • redis (RedisSSLConfig)

model_config: ClassVar[SettingsConfigDict] = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_kebab_case': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_shortcuts': None, 'cli_use_class_docs_for_groups': False, 'enable_decoding': True, 'env_file': '.env', 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_nested_max_split': None, 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'STAR_', 'env_prefix_target': 'variable', 'extra': 'ignore', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'protected_namespaces': ('model_validate', 'model_dump', 'settings_customise_sources'), 'secrets_dir': None, 'toml_file': None, 'validate_default': True, 'yaml_config_section': None, 'yaml_file': None, 'yaml_file_encoding': None}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

bot_token: str
admin_user_ids: list[str]
dangerous_command_warning_enabled: bool
dangerous_command_similarity_threshold: float
redis: RedisSSLConfig
class config.RuntimeState[source]

Bases: object

wallet_key_active: bool = False
wallet_master_key: bytes | None = None
config.load_wallet_key_non_halting(state, platform_type='eth')[source]

Load a wallet master key from the environment without aborting startup.

Reads the per-platform STAR_{PLATFORM}_WALLET_MASTER_KEY environment variable, base64-decodes it, validates that it is exactly 32 bytes (256-bit), and stashes the raw bytes on state so wallet features can come online. The function deliberately never raises: a missing or malformed key is treated as a degraded-but-bootable condition rather than a fatal error, so the rest of the bot can still serve non-wallet traffic.

On any failure it logs a loud ASCII-bordered CRITICAL warning, fires observability.alert() (tagging the hostname, wallet_key_utils component, platform, and UTC timestamp) so the missing-secret condition is visible in monitoring, and clears both wallet_key_active and wallet_master_key on state. It reads os.environ and the host name but touches no Redis/KG/LLM/HTTP collaborator. Called by the boot path and exercised directly in tests/test_boot_non_halting.py.

Parameters:
  • state (RuntimeState) – Mutable runtime container whose wallet_master_key and wallet_key_active fields are set in place to reflect the outcome.

  • platform_type (str) – Chain/platform selector (e.g. "eth") used to build the environment variable name; uppercased into STAR_{PLATFORM}_WALLET_MASTER_KEY.

Returns:

All results are communicated by mutating state.

Return type:

None

class config.PlatformConfig(type='', enabled=True, settings=<factory>)[source]

Bases: object

Configuration for a single chat platform (Matrix, Discord, webchat, …).

One entry in Config.platforms, modelling a single platform binding so the bot can run several chat surfaces side by side. The well-known type and enabled fields are promoted to attributes while every other YAML key for that platform (token, homeserver, prefix, etc.) is kept in the free-form settings mapping and read back through get().

Instances are constructed in Config.load() from the YAML platforms list (and synthesised for legacy Matrix fields / a DISCORD_TOKEN env var), and additional entries are appended at runtime by web/platforms_api.py. Consumers such as platforms/factory.py, gateway_main.py, and build_kg.py iterate the list to spin up the concrete platform clients. A plain dataclass holding configuration only — it performs no I/O.

Parameters:
type: str = ''

"matrix", "discord", etc.

Type:

Platform identifier

enabled: bool = True

Whether this platform should be started.

settings: dict[str, Any]

All remaining keys from the YAML block are stored here.

get(key, default=None)[source]

Look up a platform-specific setting, falling back to default.

Thin convenience wrapper over the free-form settings dict so callers can read per-platform options (token, homeserver, prefix, …) without reaching into the underlying mapping. Exists because the well-known type and enabled keys are promoted to dataclass attributes while everything else lands in settings.

Called heavily by platforms/factory.py when building the concrete Matrix/Discord clients (e.g. pcfg.get("token", "")) and by other platform wiring; it only reads the in-memory dict and performs no I/O.

Parameters:
  • key (str) – Name of the platform setting to read from settings.

  • default (Any) – Value returned when key is absent. Defaults to None.

Returns:

The stored setting for key, or default when not present.

Return type:

Any

class config.Config(api_key='', gemini_api_key='', llm_base_url='http://localhost:3000/openai', model='x-ai/grok-4.1-fast', temperature=0.7, max_tokens=60000, top_p=0.99, openrouter_http_connect_timeout_seconds=10.0, openrouter_http_read_timeout_seconds=1200.0, openrouter_http_write_timeout_seconds=120.0, openrouter_http_pool_timeout_seconds=180.0, system_prompt_file='system_prompt.j2', max_history=100, tools_dir='tools', tools_service_mode='in_process', tools_exec_timeout=120.0, tools_local_fallback=True, tools_force_in_process=<factory>, tools_require_session_record=True, tool_permissions=<factory>, api_keys=<factory>, prowlarr_base_url='', prowlarr_api_key='', cursor_api_key='', redis_url='', redis_sentinels=<factory>, redis_sentinel_master='falkordb', redis_tls_cert='', redis_tls_key='', redis_tls_ca='', redis_tls_verify_peer=True, redis_max_retries=3, redis_health_check_interval=15.0, redis_socket_keepalive=True, redis_socket_connect_timeout=5.0, redis_socket_timeout=0.0, embedding_model='google/gemini-embedding-001', embedding_batch_size=50, embedding_flush_interval=3600.0, vector_pg_dsn='', vector_pg_host='10.10.0.7', vector_pg_port=5432, vector_pg_database='stargazer_filerag', vector_pg_user='stargazer', vector_pg_password='', vector_pg_sslmode='prefer', vector_pg_min_size=1, vector_pg_max_size=8, kg_extraction_model='gemini-3-flash', kg_max_hops=2, kg_seed_top_k=64, kg_seed_limit=15, kg_seed_similarity_threshold=0.38, kg_seed_dynamic_threshold_enabled=True, kg_seed_dynamic_threshold_target_ratio=0.1, kg_seed_dynamic_threshold_min=0.2, kg_seed_dynamic_threshold_min_stored=5, kg_full_user_memory_ids=<factory>, kg_user_seed_min=10, kg_user_candidate_limit=100, kg_lore_candidate_limit=40, kg_lore_seed_min=5, kg_meta_candidate_limit=40, kg_meta_seed_min=5, kg_recent_speaker_limit=10, kg_min_edge_weight=0.0, kg_default_edge_weight=0.8, kg_retrieval_hop_decay=0.8, kg_expansion_neighbor_limit=500, kg_max_context_entities=30, kg_entity_dedup_threshold=0.9, kg_relationship_decay_factor=0.95, kg_per_message_extraction=False, kg_min_message_length=100, kg_per_user_extraction_limit=5, kg_extraction_channel_hints=<factory>, persona_preferences_enabled=True, persona_pref_extraction_enabled=True, persona_pref_extraction_rate_limit_seconds=180, persona_pref_extraction_min_response_length=150, persona_pref_injection_max_count=8, persona_pref_injection_max_chars=2000, persona_pref_base_persona_id='stargazer', overall_user_id_absolute_override_list=<factory>, overall_channel_id_absolute_override_list=<factory>, egregores_global_disabled=False, loopfield_global_disabled=False, ego_ablation_global_disabled=False, proactive_global_disabled=False, ncm_global_disabled=False, flash_mirror_global_disabled=False, anamnesis_global_disabled=True, cart_lock_global_enabled=False, lore_amplifier_global_disabled=False, mementropic_late_fusion_enabled=True, mementropic_semantic_weight=0.65, mementropic_resonance_weight=0.35, mementropic_ledger_max_entries=50000, mementropic_reconsolidation_enabled=True, mementropic_reconsolidation_learning_rate=0.03, mementropic_reconsolidation_max_step=0.25, mementropic_reconsolidation_max_entities=24, ka_enabled=True, ka_batch_size=20, ka_sleep_interval_seconds=300, ka_max_anchors_per_channel_per_day=300, ka_dlq_retry_limit=3, ka_backpressure_threshold=500, ka_backpressure_recovery=50, ka_batch_min_size=10, ka_epoch_size=5000, ka_fast_path_prefix='!remember', ka_extraction_http_timeout_seconds=360.0, ka_bootstrap_mode='full', ka_max_backlog_messages=1000, ka_noise_gate_enabled=True, ka_length_minimum=20, ka_similarity_familiar=0.45, ka_similarity_anomaly=0.15, ka_density_threshold=0.4, ka_tool_rate_limit_per_user_per_hour=3, ka_significant_tools=<factory>, ka_catchup_enabled=True, ka_catchup_similarity_familiar=0.55, ka_catchup_similarity_anomaly=0.2, ka_catchup_density_threshold=0.4, ka_catchup_max_anchors_per_day=3000, ka_sunset_interval_seconds=43200, ka_sunset_window_start_days=90, ka_sunset_window_end_days=80, ka_sunset_daily_summaries_per_epoch=10, ka_sunset_token_reduction_threshold=60000, ka_sunset_hydration_similarity=0.92, ka_gc_orphan_age_days=95, ka_dedup_enabled=True, ka_dedup_interval_seconds=300, ka_dedup_semantic_threshold=0.92, ka_dedup_structural_batch_size=200, ka_dedup_semantic_batch_size=50, ka_dedup_llm_retry_limit=2, ka_dedup_neighbourhood_limit=10, ka_org_enabled=True, ka_org_interval_seconds=600, ka_org_hub_degree_threshold=2, ka_org_max_hubs_per_cycle=5, ka_org_max_llm_calls_per_cycle=50, ka_org_llm_delay_seconds=0.5, ka_accum_merge_enabled=True, ka_accum_merge_threshold=10, ka_accum_merge_llm_retry_limit=2, ka_accum_merge_reembed_interval=3, dir_tree_extra_roots=<factory>, llm_filter_enabled=False, rlhf_guardrail_enabled=True, ego_ablation_enabled=False, proactive_enabled=False, proactive_default_frequency=0.05, proactive_triage_enabled=True, proactive_triage_model='gemini-3.1-flash-lite', channel_heartbeat_enabled=True, channel_heartbeat_interval_min_s=900.0, channel_heartbeat_interval_max_s=2700.0, channel_heartbeat_tick_s=45.0, channel_heartbeat_max_channels=10, channel_heartbeat_concurrency=3, channel_heartbeat_model='gemini-3-flash', background_scheduler_chat_llm_enabled=True, background_scheduler_log_rag_ingest_enabled=False, legacy_kg_extraction=False, ncm_fully_disabled_channels=<factory>, batch_window=5.0, max_batch_size=10, dna_vault_path='data/dna_vault', api_key_encryption_db_path='data/api_key_encryption_keys.db', media_cache_dir='media_cache', media_cache_max_mb=500, media_download_retry_attempts=3, visual_memory_enabled=True, visual_memory_face_threshold=0.65, visual_memory_object_threshold=0.75, visual_memory_insightface_model='buffalo_sc', visual_memory_siglip_model='google/siglip-so400m-patch14-224', visual_memory_max_entities_per_image=10, visual_memory_cache_ttl_seconds=300, visual_memory_min_sightings_to_report=2, visual_memory_text_density_threshold=0.15, user_sandboxes_dir='data/user_sandboxes', user_sandbox_quota_bytes=1073741824, user_sandbox_quota_mode='auto', user_sandbox_loopback_dir='data/user_sandbox_loopback', user_sandbox_loopback_index_path='data/user_sandbox_loopback_index.json', user_sandbox_remount_on_startup=True, tor_gateway_container='stargazer-tor-gateway', sandbox_curl_image='curlimages/curl:8.11.1', resolve_emojis_as_images=True, max_emojis_per_message=5, web_host='127.0.0.1', web_port=8080, redis_platform_admin_host='127.0.0.1', redis_platform_admin_port=8081, journal_systemd_units=<factory>, admin_user_ids=<factory>, shell_authorized_user_ids=<factory>, bot_service_name='stargazer-inference', proxy_service_name='gemini-cli-proxy', bot_repo_path='', control_unit_prefix='stargazer-', control_unit_names=<factory>, control_proxy_handler_service='gateway', control_gateway_restart_grace=8.0, control_service_restart_grace=2.0, control_reply_timeout=3.0, control_pull_lock_ttl=90, command_sync_cooldown_seconds=21600, prompt_context_build_timeout_seconds=900.0, preinference_context_shield_timeout_seconds=600.0, preinference_gather_timeout_seconds=100.0, batch_preprocess_shield_timeout_seconds=30.0, media_preprocess_shield_timeout_seconds=30.0, redis_stream_maxlen=100000, channel_semantic_recall_enabled=True, channel_semantic_recall_days=30, channel_semantic_recall_top_k=2, channel_semantic_recall_oversample_factor=5, channel_semantic_recall_neighbor_before=5, channel_semantic_recall_neighbor_after=5, channel_semantic_recall_max_total_chars=12000, channel_semantic_recall_max_window_chars=4000, channel_semantic_recall_min_similarity=0.65, channel_semantic_recall_timeout_seconds=12.0, channel_semantic_recall_cross_channel_enabled=True, channel_semantic_recall_cross_channel_top_k_channels=10, channel_semantic_recall_cross_channel_top_k_hits=2, channel_semantic_recall_cross_channel_min_similarity=0.78, channel_semantic_recall_cross_channel_max_total_chars=6000, channel_semantic_recall_cross_channel_max_window_chars=2000, channel_semantic_recall_cross_channel_neighbor_before=3, channel_semantic_recall_cross_channel_neighbor_after=3, channel_semantic_recall_cross_channel_lookback_messages=300, webhook_secret='', admin_panel_base_url='', session_cookie_domain='', discord_oauth_client_id='', discord_oauth_client_secret='', discord_oauth_redirect_uri='', oauth_encryption_key='', oauth_base_url='', oauth_providers=<factory>, platforms=<factory>, log_level='INFO', structured_logging=False, skills_enabled=False, skills_corpus_roots=<factory>, skills_index_db='data/skills_index.db', skills_top_k=12, skills_similarity_threshold=0.12, skills_catalog_max_chars=4000, mcpo_enabled=False, mcpo_base_url='', mcpo_api_key='', mcpo_config_path='data/mcpo_servers.json', dangerous_command_warning_enabled=True, dangerous_command_guard_fail_mode='open', dangerous_command_similarity_threshold=0.8, dangerous_command_benign_margin=0.0, tool_similarity_threshold=0.3, tool_top_k=15, tool_strategy_force_threshold=0.8, tool_strategy_optional_threshold=0.3, tool_group_expansion_threshold=0.55, tool_browser_similarity_threshold=0.6, starwiki_enabled=False, starwiki_root='data/starwiki', starwiki_worker_model='gemini-3-flash', starwiki_lint_interval_minutes=60, starwiki_git_author='starwiki-bot', starwiki_git_author_email='starwiki@local', starwiki_max_source_mb=25, starwiki_ingest_concurrency=2, starwiki_allow_public_wiki_edit=True, starwiki_rag_auto_index=True, starwiki_scheduled_lint_includes_public=True, attachment_guard_unreadable_truncation_enabled=True, attachment_guard_unreadable_truncation_max_chars=2000, attachment_guard_unreadable_truncation_ascii_threshold=0.05, attachment_guard_unreadable_truncation_lang_confidence=0.5, attachment_guard_unreadable_truncation_sample_chars=4096, attachment_guard_unreadable_truncation_min_letter_ratio=0.05, attachment_guard_unreadable_truncation_entropy_normalized_threshold=0.98, attachment_guard_unreadable_truncation_entropy_min_bits_per_char=3.9, attachment_guard_unreadable_truncation_entropy_min_chars=1024, homeserver='https://matrix.org', user_id='', password='', store_path='nio_store', credentials_file='credentials.json')[source]

Bases: object

Central runtime configuration for the whole bot, loaded from YAML and env.

The single source of truth for every tunable in the system — LLM/OpenRouter settings, Redis/Sentinel and mTLS wiring, the pgvector store, the knowledge graph, Limbic Anchoring, persona preferences, the web UI, OAuth, per-platform bindings, and dozens of feature toggles. It is built once via Config.load(), which reads config.yaml (plus an optional skills overlay), applies environment-variable overrides, and normalises paths and lists into the typed fields declared here.

A single loaded instance is shared across all five microservices (gateway, inference, agents, consolidation, web); each service calls Config.load() at startup and threads the object through to tools via the ToolContext. Beyond holding data it exposes a few behavioural helpers — redis_ssl_kwargs(), redis_resilience_kwargs(), and build_async_redis_client() — that turn these fields into live redis.asyncio clients, and __post_init__() syncs the global ego_ablation flag. A dataclass; construction itself performs no network I/O beyond the path canonicalisation done in load().

Parameters:
  • api_key (str)

  • gemini_api_key (str)

  • llm_base_url (str)

  • model (str)

  • temperature (float)

  • max_tokens (int)

  • top_p (float)

  • openrouter_http_connect_timeout_seconds (float)

  • openrouter_http_read_timeout_seconds (float)

  • openrouter_http_write_timeout_seconds (float)

  • openrouter_http_pool_timeout_seconds (float)

  • system_prompt_file (str)

  • max_history (int)

  • tools_dir (str)

  • tools_service_mode (str)

  • tools_exec_timeout (float)

  • tools_local_fallback (bool)

  • tools_force_in_process (list[str])

  • tools_require_session_record (bool)

  • tool_permissions (dict[str, list[str]])

  • api_keys (dict[str, Any])

  • prowlarr_base_url (str)

  • prowlarr_api_key (str)

  • cursor_api_key (str)

  • redis_url (str)

  • redis_sentinels (list[str])

  • redis_sentinel_master (str)

  • redis_tls_cert (str)

  • redis_tls_key (str)

  • redis_tls_ca (str)

  • redis_tls_verify_peer (bool)

  • redis_max_retries (int)

  • redis_health_check_interval (float)

  • redis_socket_keepalive (bool)

  • redis_socket_connect_timeout (float)

  • redis_socket_timeout (float)

  • embedding_model (str)

  • embedding_batch_size (int)

  • embedding_flush_interval (float)

  • vector_pg_dsn (str)

  • vector_pg_host (str)

  • vector_pg_port (int)

  • vector_pg_database (str)

  • vector_pg_user (str)

  • vector_pg_password (str)

  • vector_pg_sslmode (str)

  • vector_pg_min_size (int)

  • vector_pg_max_size (int)

  • kg_extraction_model (str)

  • kg_max_hops (int)

  • kg_seed_top_k (int)

  • kg_seed_limit (int)

  • kg_seed_similarity_threshold (float)

  • kg_seed_dynamic_threshold_enabled (bool)

  • kg_seed_dynamic_threshold_target_ratio (float)

  • kg_seed_dynamic_threshold_min (float)

  • kg_seed_dynamic_threshold_min_stored (int)

  • kg_full_user_memory_ids (list[str])

  • kg_user_seed_min (int)

  • kg_user_candidate_limit (int)

  • kg_lore_candidate_limit (int)

  • kg_lore_seed_min (int)

  • kg_meta_candidate_limit (int)

  • kg_meta_seed_min (int)

  • kg_recent_speaker_limit (int)

  • kg_min_edge_weight (float)

  • kg_default_edge_weight (float)

  • kg_retrieval_hop_decay (float)

  • kg_expansion_neighbor_limit (int)

  • kg_max_context_entities (int)

  • kg_entity_dedup_threshold (float)

  • kg_relationship_decay_factor (float)

  • kg_per_message_extraction (bool)

  • kg_min_message_length (int)

  • kg_per_user_extraction_limit (int)

  • kg_extraction_channel_hints (dict[str, str])

  • persona_preferences_enabled (bool)

  • persona_pref_extraction_enabled (bool)

  • persona_pref_extraction_rate_limit_seconds (int)

  • persona_pref_extraction_min_response_length (int)

  • persona_pref_injection_max_count (int)

  • persona_pref_injection_max_chars (int)

  • persona_pref_base_persona_id (str)

  • overall_user_id_absolute_override_list (list[str])

  • overall_channel_id_absolute_override_list (list[str])

  • egregores_global_disabled (bool)

  • loopfield_global_disabled (bool)

  • ego_ablation_global_disabled (bool)

  • proactive_global_disabled (bool)

  • ncm_global_disabled (bool)

  • flash_mirror_global_disabled (bool)

  • anamnesis_global_disabled (bool)

  • cart_lock_global_enabled (bool)

  • lore_amplifier_global_disabled (bool)

  • mementropic_late_fusion_enabled (bool)

  • mementropic_semantic_weight (float)

  • mementropic_resonance_weight (float)

  • mementropic_ledger_max_entries (int)

  • mementropic_reconsolidation_enabled (bool)

  • mementropic_reconsolidation_learning_rate (float)

  • mementropic_reconsolidation_max_step (float)

  • mementropic_reconsolidation_max_entities (int)

  • ka_enabled (bool)

  • ka_batch_size (int)

  • ka_sleep_interval_seconds (int)

  • ka_max_anchors_per_channel_per_day (int)

  • ka_dlq_retry_limit (int)

  • ka_backpressure_threshold (int)

  • ka_backpressure_recovery (int)

  • ka_batch_min_size (int)

  • ka_epoch_size (int)

  • ka_fast_path_prefix (str)

  • ka_extraction_http_timeout_seconds (float)

  • ka_bootstrap_mode (str)

  • ka_max_backlog_messages (int)

  • ka_noise_gate_enabled (bool)

  • ka_length_minimum (int)

  • ka_similarity_familiar (float)

  • ka_similarity_anomaly (float)

  • ka_density_threshold (float)

  • ka_tool_rate_limit_per_user_per_hour (int)

  • ka_significant_tools (list)

  • ka_catchup_enabled (bool)

  • ka_catchup_similarity_familiar (float)

  • ka_catchup_similarity_anomaly (float)

  • ka_catchup_density_threshold (float)

  • ka_catchup_max_anchors_per_day (int)

  • ka_sunset_interval_seconds (int)

  • ka_sunset_window_start_days (int)

  • ka_sunset_window_end_days (int)

  • ka_sunset_daily_summaries_per_epoch (int)

  • ka_sunset_token_reduction_threshold (int)

  • ka_sunset_hydration_similarity (float)

  • ka_gc_orphan_age_days (int)

  • ka_dedup_enabled (bool)

  • ka_dedup_interval_seconds (int)

  • ka_dedup_semantic_threshold (float)

  • ka_dedup_structural_batch_size (int)

  • ka_dedup_semantic_batch_size (int)

  • ka_dedup_llm_retry_limit (int)

  • ka_dedup_neighbourhood_limit (int)

  • ka_org_enabled (bool)

  • ka_org_interval_seconds (int)

  • ka_org_hub_degree_threshold (int)

  • ka_org_max_hubs_per_cycle (int)

  • ka_org_max_llm_calls_per_cycle (int)

  • ka_org_llm_delay_seconds (float)

  • ka_accum_merge_enabled (bool)

  • ka_accum_merge_threshold (int)

  • ka_accum_merge_llm_retry_limit (int)

  • ka_accum_merge_reembed_interval (int)

  • dir_tree_extra_roots (list[str])

  • llm_filter_enabled (bool)

  • rlhf_guardrail_enabled (bool)

  • ego_ablation_enabled (bool)

  • proactive_enabled (bool)

  • proactive_default_frequency (float)

  • proactive_triage_enabled (bool)

  • proactive_triage_model (str)

  • channel_heartbeat_enabled (bool)

  • channel_heartbeat_interval_min_s (float)

  • channel_heartbeat_interval_max_s (float)

  • channel_heartbeat_tick_s (float)

  • channel_heartbeat_max_channels (int)

  • channel_heartbeat_concurrency (int)

  • channel_heartbeat_model (str)

  • background_scheduler_chat_llm_enabled (bool)

  • background_scheduler_log_rag_ingest_enabled (bool)

  • legacy_kg_extraction (bool)

  • ncm_fully_disabled_channels (frozenset[str])

  • batch_window (float)

  • max_batch_size (int)

  • dna_vault_path (str)

  • api_key_encryption_db_path (str)

  • media_cache_dir (str)

  • media_cache_max_mb (int)

  • media_download_retry_attempts (int)

  • visual_memory_enabled (bool)

  • visual_memory_face_threshold (float)

  • visual_memory_object_threshold (float)

  • visual_memory_insightface_model (str)

  • visual_memory_siglip_model (str)

  • visual_memory_max_entities_per_image (int)

  • visual_memory_cache_ttl_seconds (int)

  • visual_memory_min_sightings_to_report (int)

  • visual_memory_text_density_threshold (float)

  • user_sandboxes_dir (str)

  • user_sandbox_quota_bytes (int)

  • user_sandbox_quota_mode (str)

  • user_sandbox_loopback_dir (str)

  • user_sandbox_loopback_index_path (str)

  • user_sandbox_remount_on_startup (bool)

  • tor_gateway_container (str)

  • sandbox_curl_image (str)

  • resolve_emojis_as_images (bool)

  • max_emojis_per_message (int)

  • web_host (str)

  • web_port (int)

  • redis_platform_admin_host (str)

  • redis_platform_admin_port (int)

  • journal_systemd_units (list[str])

  • admin_user_ids (list[str])

  • shell_authorized_user_ids (list[str])

  • bot_service_name (str)

  • proxy_service_name (str)

  • bot_repo_path (str)

  • control_unit_prefix (str)

  • control_unit_names (dict[str, str])

  • control_proxy_handler_service (str)

  • control_gateway_restart_grace (float)

  • control_service_restart_grace (float)

  • control_reply_timeout (float)

  • control_pull_lock_ttl (int)

  • command_sync_cooldown_seconds (int)

  • prompt_context_build_timeout_seconds (float)

  • preinference_context_shield_timeout_seconds (float)

  • preinference_gather_timeout_seconds (float)

  • batch_preprocess_shield_timeout_seconds (float)

  • media_preprocess_shield_timeout_seconds (float)

  • redis_stream_maxlen (int)

  • channel_semantic_recall_enabled (bool)

  • channel_semantic_recall_days (int)

  • channel_semantic_recall_top_k (int)

  • channel_semantic_recall_oversample_factor (int)

  • channel_semantic_recall_neighbor_before (int)

  • channel_semantic_recall_neighbor_after (int)

  • channel_semantic_recall_max_total_chars (int)

  • channel_semantic_recall_max_window_chars (int)

  • channel_semantic_recall_min_similarity (float)

  • channel_semantic_recall_timeout_seconds (float)

  • channel_semantic_recall_cross_channel_enabled (bool)

  • channel_semantic_recall_cross_channel_top_k_channels (int)

  • channel_semantic_recall_cross_channel_top_k_hits (int)

  • channel_semantic_recall_cross_channel_min_similarity (float)

  • channel_semantic_recall_cross_channel_max_total_chars (int)

  • channel_semantic_recall_cross_channel_max_window_chars (int)

  • channel_semantic_recall_cross_channel_neighbor_before (int)

  • channel_semantic_recall_cross_channel_neighbor_after (int)

  • channel_semantic_recall_cross_channel_lookback_messages (int)

  • webhook_secret (str)

  • admin_panel_base_url (str)

  • session_cookie_domain (str)

  • discord_oauth_client_id (str)

  • discord_oauth_client_secret (str)

  • discord_oauth_redirect_uri (str)

  • oauth_encryption_key (str)

  • oauth_base_url (str)

  • oauth_providers (dict[str, dict[str, Any]])

  • platforms (list[PlatformConfig])

  • log_level (str)

  • structured_logging (bool)

  • skills_enabled (bool)

  • skills_corpus_roots (list[str])

  • skills_index_db (str)

  • skills_top_k (int)

  • skills_similarity_threshold (float)

  • skills_catalog_max_chars (int)

  • mcpo_enabled (bool)

  • mcpo_base_url (str)

  • mcpo_api_key (str)

  • mcpo_config_path (str)

  • dangerous_command_warning_enabled (bool)

  • dangerous_command_guard_fail_mode (str)

  • dangerous_command_similarity_threshold (float)

  • dangerous_command_benign_margin (float)

  • tool_similarity_threshold (float)

  • tool_top_k (int)

  • tool_strategy_force_threshold (float)

  • tool_strategy_optional_threshold (float)

  • tool_group_expansion_threshold (float)

  • tool_browser_similarity_threshold (float)

  • starwiki_enabled (bool)

  • starwiki_root (str)

  • starwiki_worker_model (str)

  • starwiki_lint_interval_minutes (int)

  • starwiki_git_author (str)

  • starwiki_git_author_email (str)

  • starwiki_max_source_mb (int)

  • starwiki_ingest_concurrency (int)

  • starwiki_allow_public_wiki_edit (bool)

  • starwiki_rag_auto_index (bool)

  • starwiki_scheduled_lint_includes_public (bool)

  • attachment_guard_unreadable_truncation_enabled (bool)

  • attachment_guard_unreadable_truncation_max_chars (int)

  • attachment_guard_unreadable_truncation_ascii_threshold (float)

  • attachment_guard_unreadable_truncation_lang_confidence (float)

  • attachment_guard_unreadable_truncation_sample_chars (int)

  • attachment_guard_unreadable_truncation_min_letter_ratio (float)

  • attachment_guard_unreadable_truncation_entropy_normalized_threshold (float)

  • attachment_guard_unreadable_truncation_entropy_min_bits_per_char (float)

  • attachment_guard_unreadable_truncation_entropy_min_chars (int)

  • homeserver (str)

  • user_id (str)

  • password (str)

  • store_path (str)

  • credentials_file (str)

api_key: str = ''
gemini_api_key: str = ''
llm_base_url: str = 'http://localhost:3000/openai'
model: str = 'x-ai/grok-4.1-fast'
temperature: float = 0.7
max_tokens: int = 60000
top_p: float = 0.99
openrouter_http_connect_timeout_seconds: float = 10.0
openrouter_http_read_timeout_seconds: float = 1200.0
openrouter_http_write_timeout_seconds: float = 120.0
openrouter_http_pool_timeout_seconds: float = 180.0
system_prompt_file: str = 'system_prompt.j2'
max_history: int = 100
tools_dir: str = 'tools'
tools_service_mode: str = 'in_process'

How the inference tier executes tools.

  • "in_process" (default): run tools locally, exactly as before the split. Safe baseline — the dedicated tools service can be deployed dormant.

  • "remote": delegate non-pinned tools to the dedicated tools service over sg:stream:tools; gateway-pinned tools still go to the gateway and inference-pinned compound tools (INFERENCE_PINNED_TOOLS) still run locally.

  • "shadow": run remote AND in-process, keep the in-process result, log divergences (rollout validation only).

tools_exec_timeout: float = 120.0

Seconds the inference tier waits for a delegated tool result before giving up. Must exceed the TaskManager background timeout so legitimately slow tools are not abandoned early.

tools_local_fallback: bool = True

When delegation fails (tools service down / timeout), fall back to running the tool in-process for that call. Only meaningful while inference still imports the tool modules (rollout). Set False for the lean end state, where a delegation failure returns a recoverable error string to the model instead.

tools_force_in_process: list[str]

tool names that must always run in-process on inference regardless of tools_service_mode (granular rollback).

Type:

Per-tool kill switch

tools_require_session_record: bool = True

When True (default), the tools service rejects any delegated request whose trace_id has no authenticated session record (written by inference) — identity is resolved from that record, never from the request envelope. Set False only as a rollout escape hatch (falls back to envelope identity with a warning); not recommended once privileged tools run remotely.

tool_permissions: dict[str, list[str]]
api_keys: dict[str, Any]
prowlarr_base_url: str = ''
prowlarr_api_key: str = ''
cursor_api_key: str = ''
redis_url: str = ''
redis_sentinels: list[str]
redis_sentinel_master: str = 'falkordb'
redis_tls_cert: str = ''
redis_tls_key: str = ''
redis_tls_ca: str = ''
redis_tls_verify_peer: bool = True
redis_max_retries: int = 3
redis_health_check_interval: float = 15.0
redis_socket_keepalive: bool = True
redis_socket_connect_timeout: float = 5.0
redis_socket_timeout: float = 0.0
embedding_model: str = 'google/gemini-embedding-001'
embedding_batch_size: int = 50
embedding_flush_interval: float = 3600.0
vector_pg_dsn: str = ''
vector_pg_host: str = '10.10.0.7'
vector_pg_port: int = 5432
vector_pg_database: str = 'stargazer_filerag'
vector_pg_user: str = 'stargazer'
vector_pg_password: str = ''
vector_pg_sslmode: str = 'prefer'
vector_pg_min_size: int = 1
vector_pg_max_size: int = 8
kg_extraction_model: str = 'gemini-3-flash'
kg_max_hops: int = 2
kg_seed_top_k: int = 64
kg_seed_limit: int = 15
kg_seed_similarity_threshold: float = 0.38
kg_seed_dynamic_threshold_enabled: bool = True
kg_seed_dynamic_threshold_target_ratio: float = 0.1
kg_seed_dynamic_threshold_min: float = 0.2
kg_seed_dynamic_threshold_min_stored: int = 5
kg_full_user_memory_ids: list[str]
kg_user_seed_min: int = 10
kg_user_candidate_limit: int = 100
kg_lore_candidate_limit: int = 40
kg_lore_seed_min: int = 5
kg_meta_candidate_limit: int = 40
kg_meta_seed_min: int = 5
kg_recent_speaker_limit: int = 10
kg_min_edge_weight: float = 0.0
kg_default_edge_weight: float = 0.8
kg_retrieval_hop_decay: float = 0.8
kg_expansion_neighbor_limit: int = 500
kg_max_context_entities: int = 30
kg_entity_dedup_threshold: float = 0.9
kg_relationship_decay_factor: float = 0.95
kg_per_message_extraction: bool = False
kg_min_message_length: int = 100
kg_per_user_extraction_limit: int = 5
kg_extraction_channel_hints: dict[str, str]

channel_id` -> human label for KG extraction prompts.

Type:

Optional `platform

persona_preferences_enabled: bool = True

Master toggle for the persona preference memory system.

persona_pref_extraction_enabled: bool = True

Whether auto-extraction of preferences from bot responses is active.

persona_pref_extraction_rate_limit_seconds: int = 180

Minimum seconds between auto-extractions per channel.

persona_pref_extraction_min_response_length: int = 150

Skip extraction for responses shorter than this many characters.

persona_pref_injection_max_count: int = 8

Maximum number of preferences to inject per inference.

persona_pref_injection_max_chars: int = 2000

Character budget for injected preferences per inference.

persona_pref_base_persona_id: str = 'stargazer'

Identifier for the base persona (used when no egregore is active).

overall_user_id_absolute_override_list: list[str]
overall_channel_id_absolute_override_list: list[str]
egregores_global_disabled: bool = False
loopfield_global_disabled: bool = False
ego_ablation_global_disabled: bool = False
proactive_global_disabled: bool = False
ncm_global_disabled: bool = False
flash_mirror_global_disabled: bool = False
anamnesis_global_disabled: bool = True
cart_lock_global_enabled: bool = False
lore_amplifier_global_disabled: bool = False
mementropic_late_fusion_enabled: bool = True
mementropic_semantic_weight: float = 0.65
mementropic_resonance_weight: float = 0.35
mementropic_ledger_max_entries: int = 50000
mementropic_reconsolidation_enabled: bool = True
mementropic_reconsolidation_learning_rate: float = 0.03
mementropic_reconsolidation_max_step: float = 0.25
mementropic_reconsolidation_max_entities: int = 24
ka_enabled: bool = True

Master toggle for the Limbic Anchoring system.

ka_batch_size: int = 20
ka_sleep_interval_seconds: int = 300
ka_max_anchors_per_channel_per_day: int = 300
ka_dlq_retry_limit: int = 3
ka_backpressure_threshold: int = 500
ka_backpressure_recovery: int = 50
ka_batch_min_size: int = 10

Minimum backlog depth required before a batch is processed. Channels with fewer than this many pending messages are skipped (deferred) until more accumulate, preventing wasteful single-message LLM calls. Default: 10.

ka_epoch_size: int = 5000
ka_fast_path_prefix: str = '!remember'

Command prefix that triggers the fast-path explicit anchoring route.

ka_extraction_http_timeout_seconds: float = 360.0

Read timeout (seconds) for the extraction LLM HTTP call via the local proxy. Large batches with rich context can take 150-250 s on Gemini Flash; 360 s provides a comfortable margin. Raise further if timeouts persist on backpressure-doubled batches (up to ~40 messages).

ka_bootstrap_mode: str = 'full'

‘latest’ (jump to present) or ‘full’ (start from beginning).

Type:

Bootstrap mode for new channels

ka_max_backlog_messages: int = 1000

Max messages to look back when bootstrapping with ‘latest’ (e.g. to catch very recent context).

ka_noise_gate_enabled: bool = True

Toggle for the heuristic noise filtering system. If False, all messages within the daily budget are anchored.

ka_length_minimum: int = 20
ka_similarity_familiar: float = 0.45
ka_similarity_anomaly: float = 0.15
ka_density_threshold: float = 0.4
ka_tool_rate_limit_per_user_per_hour: int = 3
ka_significant_tools: list

Tool whitelist for Tool Gate; defaults to a safe production set.

ka_catchup_enabled: bool = True

Toggle catch-up gate relaxation. Set False to use normal thresholds always.

ka_catchup_similarity_familiar: float = 0.55

Familiar-path threshold during catch-up mode (wider than normal 0.45).

ka_catchup_similarity_anomaly: float = 0.2

Anomaly-path threshold during catch-up mode (lower noise band floor).

ka_catchup_density_threshold: float = 0.4

Density threshold during catch-up mode.

ka_catchup_max_anchors_per_day: int = 3000

Daily anchor budget per channel during catch-up mode.

ka_sunset_interval_seconds: int = 43200
ka_sunset_window_start_days: int = 90
ka_sunset_window_end_days: int = 80
ka_sunset_daily_summaries_per_epoch: int = 10
ka_sunset_token_reduction_threshold: int = 60000
ka_sunset_hydration_similarity: float = 0.92
ka_gc_orphan_age_days: int = 95
ka_dedup_enabled: bool = True

Master toggle for the background KG deduplication worker.

ka_dedup_interval_seconds: int = 300

every 6 hours.

Type:

How often (seconds) the dedup cycle runs. Default

ka_dedup_semantic_threshold: float = 0.92

Cosine similarity floor for Phase B (semantic) candidate pairs.

ka_dedup_structural_batch_size: int = 200

Max cross-label name collisions resolved per Phase A cycle.

ka_dedup_semantic_batch_size: int = 50

Max LLM synthesis calls issued per Phase B cycle.

ka_dedup_llm_retry_limit: int = 2

Max LLM retries per candidate pair before the pair is skipped.

ka_dedup_neighbourhood_limit: int = 10

Max relationship samples fetched per entity for the synthesis prompt.

ka_org_enabled: bool = True

Master toggle for the background KG organization worker.

ka_org_interval_seconds: int = 600

10 minutes.

Type:

How often (seconds) the organization cycle runs. Default

ka_org_hub_degree_threshold: int = 2
Type:

Relationship degree above which a node is considered a hub. Default

ka_org_max_hubs_per_cycle: int = 5

Max number of hubs evaluated per wake cycle.

ka_org_max_llm_calls_per_cycle: int = 50

Max LLM calls allowed in a single organization cycle to avoid rate limits.

ka_org_llm_delay_seconds: float = 0.5

Sleep delay between LLM calls in the organization loop to avoid rate limits.

ka_accum_merge_enabled: bool = True

Enable description accumulation and LLM consolidation for same-name+label entity hits.

ka_accum_merge_threshold: int = 10
Type:

Number of accumulated description segments before LLM consolidation fires. Default

ka_accum_merge_llm_retry_limit: int = 2

Max LLM retries for consolidation before falling back to keeping the accumulated text.

ka_accum_merge_reembed_interval: int = 3

Re-embed the entity’s accumulated description every N appends (0 = only on consolidation).

dir_tree_extra_roots: list[str]

Additional absolute filesystem paths to include in the directory tree injected into the system prompt. Set in config.yaml instead of hardcoding paths in source.

property openrouter_api_key: str

Backward-compatible alias for api_key (the OpenRouter key).

Older subsystems were written against an openrouter_api_key attribute before the field was renamed to the provider-neutral api_key; this read-only view keeps them working without a second copy of the secret.

Read by the embedding pool (gemini_embed_pool.py) and by callers that construct an OpenRouterClient such as agents_main.py, consolidation_main.py, and prompt_context.py. A trivial getter with no side effects.

Returns:

The configured OpenRouter API key (same value as api_key).

Return type:

str

property API_KEYS: dict

Upper-cased backward-compatible view of the api_keys mapping.

Exposes the external-service credential dict (Brave, Vultr, xAI, ElevenLabs, Sporestack, …) under the historical API_KEYS name that tool code was written against, e.g. ctx.config.API_KEYS["sporestack"] in tools/sporestack_tools.py. Returns the live underlying dict rather than a copy, so the same key store is shared.

Read by various tools that look up third-party service keys; a trivial getter with no side effects.

Returns:

The api_keys mapping of service name to credential.

Return type:

dict

property configured_platforms: list[str]

Return the set of enabled platform names as a lowercase list.

Scans platforms, keeping only entries that are enabled with a non-empty type, lowercases each, and collapses the self-bot variant "discord-self" to "discord" so callers see a single canonical Discord platform. The fallback trio discord, matrix, and webchat is always unioned in for backward compatibility and tests, so the result is a superset of what is strictly configured.

Read by wallet_manager.py and tools/user_variables.py (via hasattr guards) to decide which platforms a feature applies to. Pure in-memory computation over the dataclass; no I/O.

Returns:

Unique, lowercase platform identifiers (order not guaranteed since it derives from a set).

Return type:

list[str]

resolved_journal_units()[source]

systemd units the admin journal tails, honouring config then the fleet.

When journal_systemd_units is set (via YAML) that explicit list wins verbatim. Otherwise the units are derived from the canonical fleet definition — core.control_ops.SERVICE_TIERS resolved through unit_name_for — so the default automatically tracks the live microservices (stargazer-gateway, stargazer-inference, stargazer-agents, stargazer-consolidation, stargazer-web with the default prefix) and respects this deployment’s control_unit_prefix / control_unit_names overrides. The old monolithic stargazer / stargazer-swarm units no longer exist post-T3.

Read by the admin journal WebSocket in web/observability_routes.py to pick journalctl -u targets. Pure in-memory computation; no I/O. The import is deferred to keep config free of a load-time dependency on core.control_ops.

Returns:

Ordered systemd unit names to tail (never empty).

Return type:

list[str]

llm_filter_enabled: bool = False
rlhf_guardrail_enabled: bool = True
ego_ablation_enabled: bool = False
proactive_enabled: bool = False
proactive_default_frequency: float = 0.05
proactive_triage_enabled: bool = True
proactive_triage_model: str = 'gemini-3.1-flash-lite'
channel_heartbeat_enabled: bool = True
channel_heartbeat_interval_min_s: float = 900.0
channel_heartbeat_interval_max_s: float = 2700.0
channel_heartbeat_tick_s: float = 45.0
channel_heartbeat_max_channels: int = 10
channel_heartbeat_concurrency: int = 3
channel_heartbeat_model: str = 'gemini-3-flash'
background_scheduler_chat_llm_enabled: bool = True
background_scheduler_log_rag_ingest_enabled: bool = False
legacy_kg_extraction: bool = False

Whether the legacy auto_kg_extraction task is active. Disabled by default since Knowledge Anchoring does the same thing, but in real time.

ncm_fully_disabled_channels: frozenset[str]
batch_window: float = 5.0
max_batch_size: int = 10
dna_vault_path: str = 'data/dna_vault'
api_key_encryption_db_path: str = 'data/api_key_encryption_keys.db'
media_cache_dir: str = 'media_cache'
media_cache_max_mb: int = 500
media_download_retry_attempts: int = 3

Total attempts (1 = no retry) for a CDN attachment/emoji download before giving up. A transient Discord/Matrix CDN blip otherwise drops the attachment for that one message; bounded retry closes that one-shot loss.

visual_memory_enabled: bool = True

Master toggle for the visual memory graph. When False, no image processing occurs and no VisualEntity nodes are created.

visual_memory_face_threshold: float = 0.65

Cosine similarity threshold for face identity matching. ArcFace embeddings typically score 0.5-0.7 for same-person matches; 0.65 is conservative enough to avoid false positives on CPU models.

visual_memory_object_threshold: float = 0.75

Cosine similarity threshold for object/scene matching via SigLIP. Higher than face threshold because object identity is less precise.

visual_memory_insightface_model: str = 'buffalo_sc'

InsightFace model pack. buffalo_sc is CPU-friendly (small); buffalo_l is more accurate but heavier. Both use ArcFace 512d.

visual_memory_siglip_model: str = 'google/siglip-so400m-patch14-224'

HuggingFace SigLIP model for general object/scene embeddings. so400m-patch14-224 is the medium variant; CPU-manageable.

visual_memory_max_entities_per_image: int = 10

Max number of face/object entities to extract from a single image.

visual_memory_cache_ttl_seconds: int = 300

How long (seconds) recognition results stay in Redis for context injection. 5 minutes covers the typical conversation window.

visual_memory_min_sightings_to_report: int = 2

Minimum sighting count before Star reports recognizing an entity. Set to 2 so one-off sightings aren’t mentioned (avoids noise).

visual_memory_text_density_threshold: float = 0.15

Canny edge density ratio above which an image is considered text-heavy (screenshots, code, documents) and skipped for visual entity recognition. Combined with color variance and histogram bimodality checks to avoid false positives on textured photos. Range 0.0-1.0; lower = more aggressive filtering.

user_sandboxes_dir: str = 'data/user_sandboxes'

Root directory for {user_id}/workspace sandbox trees.

user_sandbox_quota_bytes: int = 1073741824

Max total size (bytes) of regular files per user under user_sandboxes_dir/{user_id}/.

user_sandbox_quota_mode: str = 'auto'

python = app-level byte counting; loopback = per-user ext4 loop image (needs Linux+root); auto = try loopback then Python.

user_sandbox_loopback_dir: str = 'data/user_sandbox_loopback'

Sparse disk images for loopback sandboxes (see docs/USER_SANDBOX_TOR.md).

user_sandbox_loopback_index_path: str = 'data/user_sandbox_loopback_index.json'

JSON map of user_id to image and mount paths for remount-after-reboot.

user_sandbox_remount_on_startup: bool = True

If True, attempt to remount loopback sandboxes when the bot starts (Linux + root).

tor_gateway_container: str = 'stargazer-tor-gateway'

Docker container name for docker run --network container:... Tor sidecar.

sandbox_curl_image: str = 'curlimages/curl:8.11.1'

Image for HTTPS downloads into a user sandbox over the Tor netns.

resolve_emojis_as_images: bool = True
max_emojis_per_message: int = 5
web_host: str = '127.0.0.1'
web_port: int = 8080
redis_platform_admin_host: str = '127.0.0.1'
redis_platform_admin_port: int = 8081
journal_systemd_units: list[str]
admin_user_ids: list[str]
shell_authorized_user_ids: list[str]
bot_service_name: str = 'stargazer-inference'

systemd unit for the back-compat !bot_restart (now an alias for !restart_inference). The old monolithic stargazer unit no longer exists post-T3; the inference tier is the closest analogue.

proxy_service_name: str = 'gemini-cli-proxy'

gemini-cli-proxy).

Type:

systemd service name for !proxy_restart (default

bot_repo_path: str = ''

Absolute path to the bot git repo for !bot_pull. Empty = current working directory.

control_unit_prefix: str = 'stargazer-'

{prefix}{service_name} (e.g. stargazer-gateway). Overridden per-service by control_unit_names.

Type:

Prefix for deriving a service’s systemd unit name

control_unit_names: dict[str, str]

Optional explicit map of service_name -> systemd unit for non-standard deployments. Falls back to control_unit_prefix + service_name when unset.

control_proxy_handler_service: str = 'gateway'

Which service tier issues !proxy_restart so the external proxy unit is restarted exactly once (not once per service that hears the control op).

control_gateway_restart_grace: float = 8.0

Seconds the gateway waits before self-restarting, so ACKs/replies flush and it restarts strictly LAST in a fleet-wide restart.

control_service_restart_grace: float = 2.0

Seconds a non-gateway service waits before self-restarting (lets it RPUSH its ack to the reply channel first).

control_reply_timeout: float = 3.0

How long the gateway publisher aggregates per-service acks before reporting.

control_pull_lock_ttl: int = 90

TTL (seconds) for the per-host/repo sg:control:pull dedupe lock.

command_sync_cooldown_seconds: int = 21600

Min seconds between gateway slash-command tree syncs (Redis NX cooldown). Boot-time auto-sync re-registers commands without tripping Discord’s rate-limit penalty box. Default 6h. Manual !sync_tree always bypasses it.

prompt_context_build_timeout_seconds: float = 900.0
preinference_context_shield_timeout_seconds: float = 600.0
preinference_gather_timeout_seconds: float = 100.0
batch_preprocess_shield_timeout_seconds: float = 30.0
media_preprocess_shield_timeout_seconds: float = 30.0
redis_stream_maxlen: int = 100000
channel_semantic_recall_enabled: bool = True
channel_semantic_recall_days: int = 30
channel_semantic_recall_top_k: int = 2
channel_semantic_recall_oversample_factor: int = 5
channel_semantic_recall_neighbor_before: int = 5
channel_semantic_recall_neighbor_after: int = 5
channel_semantic_recall_max_total_chars: int = 12000
channel_semantic_recall_max_window_chars: int = 4000
channel_semantic_recall_min_similarity: float = 0.65
channel_semantic_recall_timeout_seconds: float = 12.0
channel_semantic_recall_cross_channel_enabled: bool = True
channel_semantic_recall_cross_channel_top_k_channels: int = 10
channel_semantic_recall_cross_channel_top_k_hits: int = 2
channel_semantic_recall_cross_channel_min_similarity: float = 0.78
channel_semantic_recall_cross_channel_max_total_chars: int = 6000
channel_semantic_recall_cross_channel_max_window_chars: int = 2000
channel_semantic_recall_cross_channel_neighbor_before: int = 3
channel_semantic_recall_cross_channel_neighbor_after: int = 3
channel_semantic_recall_cross_channel_lookback_messages: int = 300
webhook_secret: str = ''
admin_panel_base_url: str = ''
discord_oauth_client_id: str = ''
discord_oauth_client_secret: str = ''
discord_oauth_redirect_uri: str = ''
oauth_encryption_key: str = ''
oauth_base_url: str = ''
oauth_providers: dict[str, dict[str, Any]]
platforms: list[PlatformConfig]
log_level: str = 'INFO'
structured_logging: bool = False
skills_enabled: bool = False
skills_corpus_roots: list[str]
skills_index_db: str = 'data/skills_index.db'
skills_top_k: int = 12
skills_similarity_threshold: float = 0.12
skills_catalog_max_chars: int = 4000
mcpo_enabled: bool = False
mcpo_base_url: str = ''
mcpo_api_key: str = ''
mcpo_config_path: str = 'data/mcpo_servers.json'
dangerous_command_warning_enabled: bool = True
dangerous_command_guard_fail_mode: str = 'open'
dangerous_command_similarity_threshold: float = 0.8
dangerous_command_benign_margin: float = 0.0
tool_similarity_threshold: float = 0.3
tool_top_k: int = 15
tool_strategy_force_threshold: float = 0.8
tool_strategy_optional_threshold: float = 0.3
tool_group_expansion_threshold: float = 0.55
tool_browser_similarity_threshold: float = 0.6
starwiki_enabled: bool = False
starwiki_root: str = 'data/starwiki'
starwiki_worker_model: str = 'gemini-3-flash'
starwiki_lint_interval_minutes: int = 60
starwiki_git_author: str = 'starwiki-bot'
starwiki_git_author_email: str = 'starwiki@local'
starwiki_max_source_mb: int = 25
starwiki_ingest_concurrency: int = 2
starwiki_allow_public_wiki_edit: bool = True
starwiki_rag_auto_index: bool = True
starwiki_scheduled_lint_includes_public: bool = True
attachment_guard_unreadable_truncation_enabled: bool = True
attachment_guard_unreadable_truncation_max_chars: int = 2000
attachment_guard_unreadable_truncation_ascii_threshold: float = 0.05
attachment_guard_unreadable_truncation_lang_confidence: float = 0.5
attachment_guard_unreadable_truncation_sample_chars: int = 4096
attachment_guard_unreadable_truncation_min_letter_ratio: float = 0.05
attachment_guard_unreadable_truncation_entropy_normalized_threshold: float = 0.98
attachment_guard_unreadable_truncation_entropy_min_bits_per_char: float = 3.9
attachment_guard_unreadable_truncation_entropy_min_chars: int = 1024
homeserver: str = 'https://matrix.org'
user_id: str = ''
password: str = ''
store_path: str = 'nio_store'
credentials_file: str = 'credentials.json'
classmethod load(path='config.yaml')[source]

Build a fully-resolved Config from YAML plus env overrides.

The primary configuration entry point for the whole bot. It reads path (default config.yaml) if present, deep-merges an optional data/skills_runtime.yaml overlay via _deep_merge_dict(), fans the nested sections out through the _parse_* helpers (knowledge graph, mementropic, persona prefs, starwiki, vector store, attachment guard, knowledge anchoring), normalises the platform list / legacy Matrix fields / tool permissions / API-key and admin-id lists, constructs the Config, and then applies typed environment-variable overrides from env_map (coercing to the field’s existing bool/int/float/str type). Finally it folds in a DISCORD_TOKEN and per-provider OAuth credentials from the environment, anchors the Redis mTLS certificate paths and the mcpo config path relative to the config file’s directory, and warns when webhook_secret is empty while bound to a public host.

Reads the filesystem (the YAML files and, via Path.resolve, the cert paths) and os.environ; it calls user_llm_config.sanitize_llm_http_url on the LLM base URL but opens no Redis/KG/LLM/HTTP connection itself. Called at startup by every service and script that needs configuration — inference_main.py, agents_main.py, consolidation_main.py, background_tasks.py, response_postprocessor.py, the KG migration scripts, and others — typically as a bare Config.load().

Parameters:

path (str | Path) – Path to the YAML config file. Defaults to "config.yaml"; a missing file is tolerated and yields a defaults-only configuration.

Returns:

A fully populated, env-overridden configuration instance.

Return type:

Config

Raises:

ValueError – Propagated from _parse_knowledge_anchoring_config() when the sunset window bounds are degenerate.

redis_ssl_kwargs()[source]

Return SSL keyword arguments for redis clients.

Returns an empty dict when mTLS is not configured, so callers can unconditionally unpack the result into Redis() / from_url().

Uses client certificate and key from redis_tls_cert / redis_tls_key. Peer (server) certificate verification is enabled strictly.

Return type:

dict

redis_resilience_kwargs()[source]

Connection-resilience kwargs for redis.asyncio clients.

Returns retry/backoff and health-check options so commands survive a Redis Sentinel failover window (master re-election) instead of raising on the first attempt. Safe to unpack into both from_url and Sentinel.master_for.

A fresh Retry is created on every call so independent connection pools do not share backoff state.

Note: socket_timeout is intentionally only included when redis_socket_timeout > 0. The primary client is shared with blocking stream/pubsub consumers (XREAD/SUBSCRIBE), and a global read timeout would sever those long-lived blocking calls.

Return type:

dict[str, Any]

build_async_redis_client(*, decode_responses=True)[source]

Build a Sentinel-aware, failover-resilient redis.asyncio client.

Mirrors MessageCache wiring so every subsystem (platform adapter, pub/sub, etc.) survives a Sentinel failover identically rather than pinning to a stale master via a bare from_url.

Prefers Sentinel (master_for) when redis_sentinels is set, otherwise falls back to from_url against redis_url.

Return type:

Any

Parameters:

decode_responses (bool)

redis_connection_kwargs_for_url(url)[source]

SSL options for redis.asyncio.from_url only when url is rediss://.

Passing TLS kwargs with a redis:// URL selects a non-SSL Connection, which does not accept ssl_* parameters and raises.

Return type:

dict[str, Any]

Parameters:

url (str)

__post_init__()[source]

Sync global ego-ablation state and downgrade local rediss:// URLs.

Dataclass post-init hook run automatically after every Config construction (including the one inside Config.load()). It imports the module-level ego_ablation and copies ego_ablation_enabled onto its global enabled flag so the killswitch takes effect process wide, then, when redis_url targets a loopback host (localhost / 127.0.0.1 / ::1) over rediss:// but no client mTLS cert/key is configured, rewrites the scheme to plain redis:// so local development does not fail a TLS handshake against a non-TLS server.

Mutates the global ego_ablation.enabled and possibly redis_url; parses the URL with urllib.parse.urlparse and swallows any exception during that rewrite. Invoked implicitly by the dataclass machinery, not called directly.

Return type:

None

Returns:

None