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:
- 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, andssl_ca_certsfields ofRedisSSLConfig. It wraps the supplied path inpathlib.Pathand 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(viaPath.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:
- Raises:
ValueError – If v does not point at an existing regular file; pydantic surfaces this as a validation error.
- 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_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)
_secrets_dir (PathType | None)
_build_sources (tuple[tuple[PydanticBaseSettingsSource, ...], dict[str, Any]] | None)
bot_token (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].
- redis: RedisSSLConfig
- 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_KEYenvironment 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
CRITICALwarning, firesobservability.alert()(tagging the hostname,wallet_key_utilscomponent, platform, and UTC timestamp) so the missing-secret condition is visible in monitoring, and clears bothwallet_key_activeandwallet_master_keyon state. It readsos.environand the host name but touches no Redis/KG/LLM/HTTP collaborator. Called by the boot path and exercised directly intests/test_boot_non_halting.py.- Parameters:
state (
RuntimeState) – Mutable runtime container whosewallet_master_keyandwallet_key_activefields 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 intoSTAR_{PLATFORM}_WALLET_MASTER_KEY.
- Returns:
All results are communicated by mutating state.
- Return type:
- class config.PlatformConfig(type='', enabled=True, settings=<factory>)[source]
Bases:
objectConfiguration 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-knowntypeandenabledfields are promoted to attributes while every other YAML key for that platform (token, homeserver, prefix, etc.) is kept in the free-formsettingsmapping and read back throughget().Instances are constructed in
Config.load()from the YAMLplatformslist (and synthesised for legacy Matrix fields / aDISCORD_TOKENenv var), and additional entries are appended at runtime byweb/platforms_api.py. Consumers such asplatforms/factory.py,gateway_main.py, andbuild_kg.pyiterate the list to spin up the concrete platform clients. A plain dataclass holding configuration only — it performs no I/O.- get(key, default=None)[source]
Look up a platform-specific setting, falling back to default.
Thin convenience wrapper over the free-form
settingsdict so callers can read per-platform options (token, homeserver, prefix, …) without reaching into the underlying mapping. Exists because the well-knowntypeandenabledkeys are promoted to dataclass attributes while everything else lands insettings.Called heavily by
platforms/factory.pywhen 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.
- 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:
objectCentral 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 readsconfig.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 theToolContext. Beyond holding data it exposes a few behavioural helpers —redis_ssl_kwargs(),redis_resilience_kwargs(), andbuild_async_redis_client()— that turn these fields into liveredis.asyncioclients, and__post_init__()syncs the globalego_ablationflag. A dataclass; construction itself performs no network I/O beyond the path canonicalisation done inload().- 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_require_session_record (bool)
prowlarr_base_url (str)
prowlarr_api_key (str)
cursor_api_key (str)
redis_url (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_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)
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)
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)
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)
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)
bot_service_name (str)
proxy_service_name (str)
bot_repo_path (str)
control_unit_prefix (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)
platforms (list[PlatformConfig])
log_level (str)
structured_logging (bool)
skills_enabled (bool)
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)
- 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 dedicatedtoolsservice oversg: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
Falsefor 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_idhas 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.
- kg_extraction_channel_hints: dict[str, str]
channel_id` -> human label for KG extraction prompts.
- Type:
Optional `platform
- 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_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).
- 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_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_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_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_neighbourhood_limit: int = 10
Max relationship samples fetched per entity for the synthesis prompt.
- 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_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_keyattribute before the field was renamed to the provider-neutralapi_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 anOpenRouterClientsuch asagents_main.py,consolidation_main.py, andprompt_context.py. A trivial getter with no side effects.- Returns:
The configured OpenRouter API key (same value as
api_key).- Return type:
- property API_KEYS: dict
Upper-cased backward-compatible view of the
api_keysmapping.Exposes the external-service credential dict (Brave, Vultr, xAI, ElevenLabs, Sporestack, …) under the historical
API_KEYSname that tool code was written against, e.g.ctx.config.API_KEYS["sporestack"]intools/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.
- property configured_platforms: list[str]
Return the set of enabled platform names as a lowercase list.
Scans
platforms, keeping only entries that areenabledwith a non-emptytype, lowercases each, and collapses the self-bot variant"discord-self"to"discord"so callers see a single canonical Discord platform. The fallback triodiscord,matrix, andwebchatis always unioned in for backward compatibility and tests, so the result is a superset of what is strictly configured.Read by
wallet_manager.pyandtools/user_variables.py(viahasattrguards) to decide which platforms a feature applies to. Pure in-memory computation over the dataclass; no I/O.
- resolved_journal_units()[source]
systemd units the admin journal tails, honouring config then the fleet.
When
journal_systemd_unitsis set (via YAML) that explicit list wins verbatim. Otherwise the units are derived from the canonical fleet definition —core.control_ops.SERVICE_TIERSresolved throughunit_name_for— so the default automatically tracks the live microservices (stargazer-gateway,stargazer-inference,stargazer-agents,stargazer-consolidation,stargazer-webwith the default prefix) and respects this deployment’scontrol_unit_prefix/control_unit_namesoverrides. The old monolithicstargazer/stargazer-swarmunits no longer exist post-T3.Read by the admin journal WebSocket in
web/observability_routes.pyto pickjournalctl -utargets. Pure in-memory computation; no I/O. The import is deferred to keepconfigfree of a load-time dependency oncore.control_ops.
- 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.
- 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_scis CPU-friendly (small);buffalo_lis 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-224is 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}/workspacesandbox 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.
- bot_service_name: str = 'stargazer-inference'
systemd unit for the back-compat
!bot_restart(now an alias for!restart_inference). The old monolithicstargazerunit 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 bycontrol_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 unitfor non-standard deployments. Falls back tocontrol_unit_prefix + service_namewhen unset.
- control_proxy_handler_service: str = 'gateway'
Which service tier issues
!proxy_restartso 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.
- 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_treealways bypasses it.
- platforms: list[PlatformConfig]
- classmethod load(path='config.yaml')[source]
Build a fully-resolved
Configfrom YAML plus env overrides.The primary configuration entry point for the whole bot. It reads path (default
config.yaml) if present, deep-merges an optionaldata/skills_runtime.yamloverlay 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 theConfig, and then applies typed environment-variable overrides fromenv_map(coercing to the field’s existing bool/int/float/str type). Finally it folds in aDISCORD_TOKENand 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 whenwebhook_secretis empty while bound to a public host.Reads the filesystem (the YAML files and, via
Path.resolve, the cert paths) andos.environ; it callsuser_llm_config.sanitize_llm_http_urlon 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 bareConfig.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:
- 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:
- redis_resilience_kwargs()[source]
Connection-resilience kwargs for
redis.asyncioclients.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_urlandSentinel.master_for.A fresh
Retryis created on every call so independent connection pools do not share backoff state.Note:
socket_timeoutis intentionally only included whenredis_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.
- build_async_redis_client(*, decode_responses=True)[source]
Build a Sentinel-aware, failover-resilient
redis.asyncioclient.Mirrors
MessageCachewiring so every subsystem (platform adapter, pub/sub, etc.) survives a Sentinel failover identically rather than pinning to a stale master via a barefrom_url.Prefers Sentinel (
master_for) whenredis_sentinelsis set, otherwise falls back tofrom_urlagainstredis_url.
- redis_connection_kwargs_for_url(url)[source]
SSL options for
redis.asyncio.from_urlonly when url isrediss://.Passing TLS kwargs with a
redis://URL selects a non-SSLConnection, which does not acceptssl_*parameters and raises.
- __post_init__()[source]
Sync global ego-ablation state and downgrade local
rediss://URLs.Dataclass post-init hook run automatically after every
Configconstruction (including the one insideConfig.load()). It imports the module-levelego_ablationand copiesego_ablation_enabledonto its globalenabledflag so the killswitch takes effect process wide, then, whenredis_urltargets a loopback host (localhost/127.0.0.1/::1) overrediss://but no client mTLS cert/key is configured, rewrites the scheme to plainredis://so local development does not fail a TLS handshake against a non-TLS server.Mutates the global
ego_ablation.enabledand possiblyredis_url; parses the URL withurllib.parse.urlparseand swallows any exception during that rewrite. Invoked implicitly by the dataclass machinery, not called directly.- Return type:
- Returns:
None