{
  "_lang": "en",
  "nav": {
    "core": "Core",
    "configure": "Configure",
    "automate": "Automate",
    "observe": "Observe",
    "advanced": "Advanced",
    "config": "Configuration",
    "automation": "Automation",
    "resources": "Resources",
    "system": "System",
    "overview": "Overview",
    "canvas": "Canvas",
    "chat": "Chat",
    "sessions": "Sessions",
    "approvals": "Approvals",
    "workflows": "Workflows",
    "scheduler": "Scheduler",
    "goals": "Goals",
    "agents": "Agents",
    "users": "Users",
    "providers": "Providers",
    "channels": "Channels",
    "skills": "Skills",
    "hands": "Hands",
    "plugins": "Plugins",
    "mcp_servers": "MCP",
    "models": "Models",
    "media": "Media",
    "analytics": "Analytics",
    "memory": "Memory",
    "comms": "Comms",
    "runtime": "Runtime",
    "audit": "Audit",
    "logs": "Logs",
    "settings": "Settings",
    "network": "Network",
    "a2a": "A2A",
    "telemetry": "Telemetry",
    "terminal": "Terminal",
    "user_center": "User Center",
    "logout": "Logout",
    "shortcuts": "Docs & shortcuts",
    "runtime_section": "Runtime",
    "observability": "Observability",
    "admin": "Admin",
    "expand_sidebar": "Expand sidebar",
    "collapse_sidebar": "Collapse sidebar",
    "open_menu": "Open navigation menu",
    "skip_to_content": "Skip to content",
    "more": "More",
    "mobile_tabs": "Bottom navigation"
  },
  "common": {
    "copied": "Copied",
    "copy_failed": "Copy failed",
    "show": "Show",
    "hide": "Hide",
    "refresh": "Refresh",
    "status": "Status",
    "daemon_online": "Daemon Online",
    "infrastructure": "Infrastructure",
    "toggle_theme": "Toggle theme",
    "change_language": "Change language",
    "theme": "Theme",
    "light": "Light",
    "dark": "Dark",
    "language": "Language",
    "user": "User",
    "delete": "Delete",
    "all": "All",
    "cancel": "Cancel",
    "save": "Save",
    "saving": "Saving...",
    "edit": "Edit",
    "confirm": "Confirm",
    "loading": "Loading...",
    "search": "Search",
    "back": "Back",
    "retry": "Retry",
    "create": "Create",
    "creating": "Creating...",
    "name": "Name",
    "description": "Description",
    "detail": "Detail",
    "actions": "Actions",
    "clear": "Clear",
    "load": "Load",
    "active": "Active",
    "idle": "Idle",
    "running": "Running",
    "online": "Online",
    "offline": "Offline",
    "setup": "Setup",
    "ok": "OK",
    "config": "Config",
    "interact": "Interact",
    "never": "Never",
    "just_now": "just now",
    "settings": "Settings",
    "unknown": "Unknown",
    "no_data": "No data",
    "resume": "Resume",
    "close": "Close",
    "clear_search": "Clear search",
    "select": "Select",
    "deselect": "Deselect",
    "yes": "Yes",
    "no": "No",
    "details": "Details",
    "kernel_runtime": "Kernel Runtime",
    "run_now": "Run Now",
    "view_all": "View All",
    "created": "Created",
    "check": "Check",
    "label": "Label",
    "local": "Local",
    "properties": "Properties",
    "success": "Success",
    "type": "Type",
    "symbols": {
      "separator": ":",
      "arrow": "→",
      "none": "-",
      "slash": "/",
      "expand": "+",
      "collapse": "−"
    },
    "units": {
      "mb": "MB",
      "ms": "ms",
      "days_short": "d",
      "hours_short": "h",
      "minutes_short": "m",
      "seconds_short": "s"
    },
    "copy": "Copy",
    "add_more": "Add more…",
    "press_enter_to_add": "press Enter to add \"{{value}}\"",
    "always": "Always",
    "auto": "Auto",
    "clear_filters": "Clear filters",
    "continue": "Continue",
    "disabled": "OFF",
    "error": "Error",
    "help": "Help",
    "next": "Next",
    "no_results": "No results",
    "off": "Off",
    "previous": "Previous",
    "saved": "Saved",
    "sort_by": "Sort",
    "sort_created": "Created",
    "sort_last_active": "Last active",
    "sort_name": "Name",
    "viewAll": "View All",
    "on": "ON",
    "expand": "Expand",
    "collapse": "Collapse",
    "show_advanced": "Show advanced",
    "hide_advanced": "Hide advanced",
    "add": "Add",
    "remove": "Remove",
    "discard": "Discard",
    "more_actions": "More actions",
    "currency_symbol": "$",
    "unlimited": "∞",
    "none": "None",
    "metadata": "Metadata",
    "size": "Size",
    "path": "Path"
  },
  "status": {
    "running": "Running",
    "idle": "Idle",
    "error": "Error",
    "active": "Active",
    "paused": "Paused",
    "configured": "Configured",
    "nominal": "Nominal",
    "unknown": "Unknown"
  },
  "overview": {
    "welcome": "Welcome to LibreFang",
    "description": "Manage your autonomous agent infrastructure and multi-channel workflows.",
    "system_overview": "System Overview",
    "operational": "Operational",
    "alert": "System Alert",
    "active_agents": "Active Agents",
    "active": "active",
    "total": "total",
    "active_count": "{{count}} active",
    "workflows": "Workflows",
    "design_with_canvas": "Design with visual canvas",
    "providers": "Providers",
    "configured": "configured",
    "channels": "Channels",
    "adapters_available": "adapters available",
    "quick_actions": "Quick Actions",
    "new_workflow": "New Workflow",
    "deploy_agent": "Deploy Agent",
    "open_chat": "Open Chat",
    "recent_agents": "Recent Agents",
    "view_all": "View All",
    "system_status": "System Status",
    "uptime": "Uptime",
    "memory_usage": "Memory",
    "version": "Version",
    "telemetry": "Service Telemetry",
    "pro_tip": "Pro Tip",
    "pro_tip_text": "Use the Canvas to orchestrate agents across multiple channels.",
    "no_active_agents": "No active agents configured",
    "no_telemetry": "No telemetry data available",
    "active_sessions": "Active Sessions",
    "agent_count": "Agent Count",
    "health_checks": "Health Checks",
    "pro_tip_shortcut": "⌘K to search · / to focus search · ? for all shortcuts · g then letter to navigate",
    "setup_title": "Setup Required",
    "setup_description": "No configuration file detected. Click to auto-detect your LLM provider and generate a default config.",
    "setup_button": "Initialize",
    "setup_running": "Initializing...",
    "setup_wizard": "Use Wizard",
    "last_updated": "Last updated",
    "recent_sessions": "Recent sessions",
    "agents_online": "agents online",
    "loading_runtime": "Loading runtime…",
    "no_agents": "No agents yet",
    "no_token_data": "No token usage yet",
    "idle": "idle",
    "error": "error",
    "refresh": "Refresh",
    "refreshing": "Refreshing…",
    "new_agent": "New agent",
    "updated": "updated",
    "tokens_by_agent": "Tokens by agent · all-time",
    "kpi": {
      "active_agents": "Active agents",
      "configured": "configured",
      "spend": "Spend",
      "prior": "prior",
      "no_prior": "no prior spend",
      "tokens_over_7d": "tokens over 7d",
      "peak": "tokens/s peak",
      "p95_latency": "P95 latency",
      "default_model": "default model"
    },
    "range": {
      "7d": "7 days",
      "30d": "30 days",
      "90d": "90 days"
    },
    "cost": {
      "title": "Cost",
      "vs_prior": "vs prior",
      "no_prior": "no prior spend",
      "provider_all_time": "provider share all-time"
    },
    "alerts": {
      "title": "Alerts",
      "active": "active",
      "show_less": "Show less",
      "all_clear": "All clear.",
      "systems_ok": "All systems operational",
      "restore": "Restore",
      "restore_count": "Restore {{count}} dismissed",
      "agent_failed": "{{name}} failed",
      "agent_failed_sub": "Restart from Agents page",
      "mcp_degraded": "{{count}} MCP server(s) degraded",
      "connected": "connected",
      "approvals_pending": "{{count}} approval(s) pending",
      "approvals_pending_sub": "Review in Approvals queue",
      "degraded": "Degraded"
    },
    "col": {
      "agent": "Agent",
      "model": "Model",
      "profile": "Profile",
      "mode": "Mode",
      "last_active": "Last active",
      "task": "Task",
      "msgs": "Msgs",
      "started": "Started",
      "no_label": "(no label)"
    },
    "system": {
      "runtime": "Runtime",
      "memory": "Memory",
      "scheduler": "Scheduler",
      "mcp": "MCP",
      "network": "Network",
      "audit": "Audit",
      "audit_value": "append-only · OK",
      "active": "active",
      "no_schedules": "no schedules",
      "servers": "servers",
      "degraded": "deg",
      "peers": "peers",
      "no_peers": "no peers"
    }
  },
  "agents": {
    "title": "Agents",
    "subtitle": "Active autonomous units managed by the LibreFang kernel.",
    "model": "Model",
    "provider": "Provider",
    "max_tokens": "Max Tokens",
    "temperature": "Temperature",
    "last_active": "Last Active",
    "no_matching": "No agents matching your search.",
    "system_prompt": "System Prompt",
    "web_search": "Web Search",
    "web_search_augmentation": "Search Augmentation",
    "web_search_augmentation_hint": "Auto-search the web and inject results into context before LLM call",
    "capabilities": "Capabilities",
    "skills": "Skills",
    "tags": "Tags",
    "mode": "Mode",
    "create_agent": "Create Agent",
    "from_form": "From Form",
    "from_template": "From Template",
    "from_toml": "From TOML",
    "template_name": "Template Name",
    "template_placeholder": "-- Select a template --",
    "template_custom_name": "Agent Name (optional)",
    "template_custom_name_placeholder": "Leave blank to use template default",
    "template_custom_name_hint": "Override the template's default name so you can run multiple agents from the same template.",
    "edit_template_toml": "Edit TOML for advanced customization →",
    "loading_template_toml": "Loading template…",
    "loading_template_toml_failed": "Failed to load template TOML",
    "agent_created": "Agent created",
    "create_failed": "Failed to create agent",
    "manifest_toml": "Agent Manifest (TOML)",
    "thinking_toml_hint": "Add a [thinking] section in TOML to enable extended thinking",
    "schedule_manual": "manual",
    "kpi": {
      "sessions": "Sessions · 24h",
      "sessions_idle": "idle",
      "cost": "Cost · 24h",
      "p95": "P95 latency",
      "samples": "{{count}} samples",
      "tools": "Tools"
    },
    "form": {
      "basics": "Basics",
      "model": "Model",
      "resources": "Resources & Budgets",
      "capabilities": "Capabilities",
      "discovery": "Discovery",
      "name": "Agent Name",
      "description": "Description",
      "description_placeholder": "What does this agent do?",
      "version": "Version",
      "author": "Author",
      "provider": "Provider",
      "select_provider": "-- Select provider --",
      "model_id": "Model",
      "select_model": "-- Select model --",
      "system_prompt": "System Prompt",
      "system_prompt_placeholder": "You are a helpful AI agent.",
      "temperature": "Temperature",
      "max_tokens": "Max Tokens",
      "tokens_per_hour": "LLM Tokens / Hour",
      "tool_calls_per_minute": "Tool Calls / Minute",
      "cost_per_hour": "Max Cost / Hour ($)",
      "cost_per_day": "Max Cost / Day ($)",
      "inherit_default": "inherit default",
      "network_hosts": "Allowed Network Hosts",
      "network_hosts_hint": "host:port pairs the agent may reach (e.g. api.openai.com:443). Empty = no network access.",
      "shell_commands": "Allowed Shell Commands",
      "shell_commands_hint": "Command names the agent may execute. Empty = no shell access.",
      "agent_spawn": "Can spawn sub-agents",
      "ofp_discover": "Can discover OFP peers",
      "enabled": "Enabled at startup",
      "tags": "Tags",
      "tags_placeholder": "beta, research",
      "skills": "Skills",
      "skills_placeholder": "Empty = all skills available",
      "skills_hint": "Empty = all installed skills available.",
      "skills_search_placeholder": "Search installed skills…",
      "mcp_servers": "MCP Servers",
      "mcp_servers_placeholder": "Empty = all connected servers",
      "mcp_servers_hint": "Empty = all configured MCP servers available.",
      "mcp_servers_search_placeholder": "Search MCP servers…",
      "live_toml": "Live TOML Preview",
      "preview_toml": "TOML",
      "preview_markdown": "Markdown",
      "switch_to_toml": "Switch to TOML →",
      "toml_parse_error": "TOML parse error: {{msg}}",
      "copy": "Copy to clipboard",
      "copied": "Copied to clipboard",
      "module": "Module",
      "priority": "Priority",
      "priority_low": "Low",
      "priority_normal": "Normal",
      "priority_high": "High",
      "priority_critical": "Critical",
      "api_key_env": "API Key Env Var",
      "api_key_env_hint": "Name of the env var holding the API key (e.g. OPENAI_API_KEY).",
      "base_url": "Base URL Override",
      "cost_per_month": "Max Cost / Month ($)",
      "network_bytes_per_hour": "Network Bytes / Hour",
      "memory_bytes": "Max Memory (bytes)",
      "cpu_time_ms": "Max CPU Time (ms)",
      "cap_tools": "Tool ID Allowlist",
      "cap_tools_hint": "Tool IDs the agent is permitted to invoke. Empty = no restriction at this layer.",
      "cap_tools_search_placeholder": "Search tools…",
      "memory_read": "Memory Read Scopes",
      "memory_write": "Memory Write Scopes",
      "agent_message": "Agent Message Targets",
      "ofp_connect": "OFP Connect Patterns",
      "scheduling": "Scheduling",
      "schedule_mode": "Schedule Mode",
      "schedule_mode_hint": "Reactive = wake on event. Periodic = cron. Proactive = condition watcher. Continuous = persistent loop.",
      "schedule_reactive": "Reactive (default)",
      "schedule_periodic": "Periodic (cron)",
      "schedule_proactive": "Proactive (conditions)",
      "schedule_continuous": "Continuous loop",
      "cron": "Cron Expression",
      "conditions": "Trigger Conditions",
      "check_interval_secs": "Check Interval (seconds)",
      "fallback_models": "Fallback Models",
      "fallback_models_hint": "Tried in order if the primary model fails.",
      "add_fallback": "Add fallback",
      "thinking": "Extended Thinking",
      "thinking_enabled": "Enable per-agent thinking config",
      "budget_tokens": "Budget Tokens",
      "stream_thinking": "Stream Thinking",
      "autonomous": "Autonomous Guardrails",
      "autonomous_enabled": "Enable autonomous mode",
      "max_iterations": "Max Iterations / Run",
      "max_restarts": "Max Restarts",
      "heartbeat_interval_secs": "Heartbeat Interval (s)",
      "heartbeat_timeout_secs": "Heartbeat Timeout (s)",
      "heartbeat_keep_recent": "Heartbeat Keep Recent",
      "heartbeat_channel": "Heartbeat Channel",
      "quiet_hours": "Quiet Hours (cron)",
      "routing": "Model Routing",
      "routing_enabled": "Enable complexity-based routing",
      "simple_model": "Simple",
      "medium_model": "Medium",
      "complex_model": "Complex",
      "simple_threshold": "Simple Threshold (tokens)",
      "complex_threshold": "Complex Threshold (tokens)",
      "context_injection": "Context Injections",
      "context_injection_hint": "Auto-inject content into the session before the LLM call.",
      "add_injection": "Add injection",
      "injection_name": "Name (for logs)",
      "injection_content": "Content",
      "injection_condition": "Condition (optional, e.g. agent.tags contains 'chat')",
      "position_system": "System (top of prompt)",
      "position_before_user": "Before user message",
      "position_after_reset": "After reset prompt",
      "response_format": "Response Format",
      "response_format_mode": "Format Mode",
      "response_text": "Text (default)",
      "response_json": "JSON object",
      "response_json_schema": "JSON Schema",
      "schema_name": "Schema Name",
      "schema_body": "Schema (JSON)",
      "strict": "Strict schema adherence",
      "lifecycle": "Lifecycle & Overrides",
      "session_mode": "Session Mode",
      "session_persistent": "Persistent (reuse session)",
      "session_new": "New (fresh session each run)",
      "web_search_aug": "Web Search Augmentation",
      "web_search_off": "Off",
      "web_search_auto": "Auto (when model lacks tool calling)",
      "web_search_always": "Always",
      "exec_policy": "Exec Policy",
      "exec_policy_global": "(use global policy)",
      "exec_policy_extras_hint": "TOML carries a custom [exec_policy] table that this dropdown can't represent. The table will still be sent on submit. Pick a shorthand to override it.",
      "response_format_extras_hint": "TOML carries a [response_format] table with an unrecognised type. It will still be sent on submit. Pick json or json_schema to override.",
      "pinned_model": "Pinned Model",
      "workspace": "Workspace Path",
      "allowed_plugins": "Allowed Plugins",
      "allowed_plugins_placeholder": "Empty = all installed plugins",
      "skills_disabled": "Disable all skills",
      "tools_disabled": "Disable all tools",
      "inherit_parent_context": "Inherit parent context (subagents)",
      "generate_identity_files": "Generate workspace identity files",
      "name_placeholder": "e.g. my-agent",
      "module_placeholder": "e.g. default",
      "model_id_placeholder": "e.g. gpt-4o",
      "temperature_placeholder": "0.7",
      "max_tokens_placeholder": "4096",
      "api_key_env_placeholder": "OPENAI_API_KEY",
      "base_url_placeholder": "https://api.example.com/v1",
      "tool_calls_per_minute_placeholder": "60",
      "unlimited_placeholder": "0 = unlimited",
      "network_bytes_placeholder": "0 = unlimited",
      "memory_bytes_placeholder": "0 = unlimited",
      "cpu_time_placeholder": "0 = unlimited",
      "network_hosts_placeholder": "api.openai.com:443",
      "shell_commands_placeholder": "ls, cat, grep",
      "cap_tools_placeholder": "web_search, file_read",
      "memory_glob_placeholder": "agent:*",
      "agent_message_placeholder": "agent-name",
      "ofp_connect_placeholder": "/ip4/0.0.0.0/tcp/4001",
      "cron_hint": "Standard 5-field cron expression (e.g. 0 */6 * * *)",
      "cron_placeholder": "0 */6 * * *",
      "conditions_placeholder": "agent.queue_depth > 10",
      "check_interval_placeholder": "300",
      "budget_tokens_placeholder": "8192",
      "max_iterations_placeholder": "50",
      "max_restarts_placeholder": "3",
      "heartbeat_interval_placeholder": "60",
      "auto_placeholder": "auto",
      "heartbeat_channel_placeholder": "heartbeat",
      "quiet_hours_hint": "Cron expression for times when the agent should not run (e.g. 0 22 * * *)",
      "quiet_hours_placeholder": "0 22 * * *",
      "simple_threshold_placeholder": "512",
      "complex_threshold_placeholder": "2048",
      "schema_name_placeholder": "my_schema"
    },
    "delete_confirm": "Are you sure you want to delete agent \"{{name}}\"?",
    "prompts": "Prompts",
    "prompts_experiments": {
      "title": "Prompts & Experiments",
      "versions_tab": "Versions",
      "experiments_tab": "Experiments",
      "new_version": "New Version",
      "new_experiment": "New Experiment",
      "active": "Active",
      "activate": "Activate",
      "no_versions": "No prompt versions yet",
      "create_version_title": "Create Prompt Version",
      "system_prompt": "System Prompt",
      "description_optional": "Description (optional)",
      "no_experiments": "No experiments yet",
      "start": "Start",
      "pause": "Pause",
      "complete": "Complete",
      "metrics": "Metrics",
      "experiment_metrics": "Experiment Metrics",
      "requests": "Requests",
      "avg_latency": "Avg Latency",
      "avg_cost": "Avg Cost",
      "close_metrics": "Close Metrics",
      "create_experiment_title": "Create Experiment",
      "experiment_name": "Experiment Name",
      "select_versions": "Select Prompt Versions (min 2)",
      "create_versions_first": "Create at least 2 prompt versions first.",
      "control": "Control",
      "create_with_variants": "Create ({{count}} variants)",
      "variants_count": "{{count}} variants",
      "created_label": "Created:",
      "ok_label": "ok",
      "err_label": "err",
      "system_prompt_placeholder": "You are a helpful AI assistant...",
      "description_placeholder": "What's different in this version?",
      "experiment_name_placeholder": "My A/B Test"
    },
    "thinking": "Extended Thinking",
    "thinking_enabled": "Enabled",
    "budget_tokens": "Thinking Budget (tokens)",
    "stream_thinking": "Stream Thinking",
    "thinking_hint": "Extended thinking lets the model reason deeply before answering",
    "clone": "Clone",
    "reset": "Reset",
    "reset_confirm": "Are you sure you want to reset this agent's session? Chat history will be cleared.",
    "suspend": "Suspend",
    "resume": "Resume",
    "core_agents": "Core Agents",
    "hands": "Hands",
    "hand_badge": "HAND",
    "show_hand_agents": "Show hand agents",
    "filter_all": "All",
    "filter_running": "Running",
    "filter_suspended": "Suspended",
    "hand_agent_hint": "You are editing the active runtime agent created by a hand. Changes live in memory only and will revert to the hand's configuration when the daemon restarts or the hand is reloaded.",
    "tools_cap": "Tools",
    "network": "Network",
    "help": "Agents are the autonomous units this LibreFang instance runs. Each agent has its own identity, prompt, tool set, memory, and budget — and lives as a row on this page until you delete it. From here you create new agents, edit existing ones, suspend / resume them, and clone working setups.\n\nHow to use this page:\n\n1. Create. Click \"Create agent\" and pick a creation mode: form, template, or raw TOML. The form is the easiest way in; templates are pre-built archetypes (researcher, coder, …); TOML is the raw manifest if you already know what you want.\n\n2. Inspect & edit. Click an agent row to open its detail panel — see its capabilities, hands, model, recent activity. Use \"Edit\" to change name, prompt, model, or tool policy. Use \"Edit template TOML\" to hand-edit the full manifest.\n\n3. Lifecycle. Suspend pauses an agent (stops triggers, keeps state). Resume brings it back. Clone copies the manifest to a new agent so you can fork without breaking the original. Delete is permanent — sessions and memory go with it.\n\nTypical scenarios:\n\n  · Spinning up a per-domain agent (research / code / ops) and giving each its own channel and budget.\n  · Forking an agent that works well, tweaking the prompt, A/B-testing the variants in parallel.\n  · Suspending agents during quota crunches without losing their config or memory.\n\nThings to know:\n\n  · The agent.toml manifest controls runtime behaviour — session_mode, max_concurrent_invocations, max_history_messages, named workspaces. The form covers the common cases; the TOML editor is the escape hatch.\n  · Identity files (SOUL.md, IDENTITY.md, …) live in {workspace}/.identity/. They migrate automatically on first spawn after upgrade.\n  · Deleting an agent is irreversible. Suspend first if you might want it back.",
    "builtin": {
      "academic-researcher": {
        "name": "Academic Researcher",
        "description": "Academic research agent. Searches scholarly papers, summarizes findings, and generates literature reviews."
      },
      "analyst": {
        "name": "Analyst",
        "description": "Data analyst. Processes data, generates insights, creates reports."
      },
      "architect": {
        "name": "Architect",
        "description": "System architect. Designs software architectures, evaluates trade-offs, creates technical specifications."
      },
      "assistant": {
        "name": "Assistant",
        "description": "General-purpose assistant agent. The default agent for everyday tasks, questions, and conversations."
      },
      "code-reviewer": {
        "name": "Code Reviewer",
        "description": "Senior code reviewer. Reviews PRs, identifies issues, suggests improvements with production standards."
      },
      "coder": {
        "name": "Coder",
        "description": "Expert software engineer. Reads, writes, and analyzes code."
      },
      "customer-support": {
        "name": "Customer Support",
        "description": "Customer support agent for ticket handling, issue resolution, and customer communication."
      },
      "data-scientist": {
        "name": "Data Scientist",
        "description": "Data scientist. Analyzes datasets, builds models, creates visualizations, performs statistical analysis."
      },
      "debugger": {
        "name": "Debugger",
        "description": "Expert debugger. Traces bugs, analyzes stack traces, performs root cause analysis."
      },
      "devops-lead": {
        "name": "DevOps Lead",
        "description": "DevOps lead. Manages CI/CD, infrastructure, deployments, monitoring, and incident response."
      },
      "doc-writer": {
        "name": "Doc Writer",
        "description": "Technical writer. Creates documentation, README files, API docs, tutorials, and architecture guides."
      },
      "email-assistant": {
        "name": "Email Assistant",
        "description": "Email triage, drafting, scheduling, and inbox management agent."
      },
      "hello-world": {
        "name": "Hello World",
        "description": "A friendly greeting agent that can read files, search the web, and answer everyday questions."
      },
      "home-automation": {
        "name": "Home Automation",
        "description": "Smart home control agent for IoT device management, automation rules, and home monitoring."
      },
      "legal-assistant": {
        "name": "Legal Assistant",
        "description": "Legal assistant agent for contract review, legal research, compliance checking, and document drafting."
      },
      "meeting-assistant": {
        "name": "Meeting Assistant",
        "description": "Meeting notes, action items, agenda preparation, and follow-up tracking agent."
      },
      "ops": {
        "name": "Ops",
        "description": "DevOps agent. Monitors systems, runs diagnostics, manages deployments."
      },
      "orchestrator": {
        "name": "Orchestrator",
        "description": "Meta-agent that decomposes complex tasks, delegates to specialist agents, and synthesizes results."
      },
      "personal-finance": {
        "name": "Personal Finance",
        "description": "Personal finance agent for budget tracking, expense analysis, savings goals, and financial planning."
      },
      "planner": {
        "name": "Planner",
        "description": "Project planner. Creates project plans, breaks down epics, estimates effort, identifies risks and dependencies."
      },
      "recipe-assistant": {
        "name": "Recipe Assistant",
        "description": "Cooking assistant that helps with recipes, meal plans, ingredient substitutions, and portion adjustments."
      },
      "recruiter": {
        "name": "Recruiter",
        "description": "Recruiting agent for resume screening, candidate outreach, job description writing, and hiring pipeline management."
      },
      "researcher": {
        "name": "Researcher",
        "description": "Research agent. Fetches web content and synthesizes information."
      },
      "sales-assistant": {
        "name": "Sales Assistant",
        "description": "Sales assistant agent for CRM updates, outreach drafting, pipeline management, and deal tracking."
      },
      "security-auditor": {
        "name": "Security Auditor",
        "description": "Security specialist. Reviews code for vulnerabilities, checks configurations, performs threat modeling."
      },
      "social-media": {
        "name": "Social Media",
        "description": "Social media content creation, scheduling, and engagement strategy agent."
      },
      "test-engineer": {
        "name": "Test Engineer",
        "description": "Quality assurance engineer. Designs test strategies, writes tests, validates correctness."
      },
      "translator": {
        "name": "Translator",
        "description": "Multi-language translation agent for document translation, localization, and cross-cultural communication."
      },
      "travel-planner": {
        "name": "Travel Planner",
        "description": "Trip planning agent for itinerary creation, booking research, budget estimation, and travel logistics."
      },
      "tutor": {
        "name": "Tutor",
        "description": "Teaching and explanation agent for learning, tutoring, and educational content creation."
      },
      "writer": {
        "name": "Writer",
        "description": "Content writer. Creates documentation, articles, and technical writing."
      }
    },
    "clone_failed": "Failed to clone agent",
    "delete_failed": "Failed to delete agent",
    "delete_success": "Agent deleted",
    "delete_title": "Delete agent?",
    "edit_name": "Agent name",
    "model_save_failed": "Failed to update model",
    "model_saved": "Model updated",
    "rename_failed": "Failed to rename agent",
    "rename_hand_disabled": "Hand-managed agents cannot be renamed",
    "rename_hint": "Click to rename",
    "rename_success": "Agent renamed",
    "reset_title": "Reset session?",
    "resume_failed": "Failed to resume agent",
    "suspend_failed": "Failed to suspend agent",
    "tools_allowed_count": "allowed",
    "tools_allowlist_desc": "These tools are explicitly allowed. Leave empty to allow all tools except blocked ones.",
    "tools_allowlist_title": "Allowlist",
    "tools_available": "tools available",
    "tools_blocked_count": "blocked",
    "tools_blocklist_desc": "These tools are blocked even if they are present in the allowlist.",
    "tools_blocklist_title": "Blocklist",
    "tools_conflict_warning": "{{count}} tools are in both lists. Blocklist wins and those tools will be removed from the allowlist when you save.",
    "tools_disabled_hint": "Tools are currently enabled. Allowlist and blocklist below control which tools remain available.",
    "tools_disabled_hint_active": "Tools are disabled for this agent; editing allow/block filters is blocked here. Re-enable tools in the agent config to manage filters.",
    "tools_disabled_label": "Disable all tools",
    "tools_disabled_save_blocked": "All tools are disabled for this agent. To re-enable tools, edit the agent manifest or config directly — this editor only manages allow/block filters.",
    "tools_disabled_save_hint": "Re-enable tools in the agent config to modify filters",
    "tools_edit_aria": "Edit tools",
    "tools_editor_desc": "Review the current tools state for this agent. Empty allowlist means no allow restriction; blocklist still removes selected tools.",
    "tools_editor_title": "Agent Tools",
    "tools_load_failed": "Failed to load tools",
    "tools_save_failed": "Failed to update tools",
    "tools_saved": "Tools updated",
    "tools_saved_conflicts": "Tools updated. Conflicts were resolved in favor of the blocklist.",
    "tools_search_placeholder": "Search tools...",
    "detail": {
      "schedule_mode": "Mode",
      "schedule_manual": "Manual",
      "schedule_manual_desc": "wakes on incoming messages and events only",
      "schedule_continuous": "Continuous",
      "schedule_continuous_desc": "agent checks for work on a fixed interval",
      "schedule_periodic": "Periodic",
      "schedule_periodic_desc": "agent fires on the cron expression set in the manifest — edit via agent.toml",
      "schedule_proactive": "Proactive",
      "schedule_proactive_desc": "agent monitors conditions set in the manifest — edit via agent.toml",
      "schedule_manifest_only": "manifest-controlled",
      "switch_to_continuous": "Switch to continuous",
      "switch_to_manual": "Switch to manual",
      "check_interval_secs": "Check interval (seconds)",
      "schedule_invalid_interval": "Interval must be a positive integer (seconds)",
      "schedule_updated": "Schedule updated",
      "cron_jobs": "Cron jobs",
      "add_cron": "Add cron",
      "no_cron": "No cron jobs",
      "event_triggers": "Event triggers",
      "add_trigger": "Add trigger",
      "no_triggers": "No event triggers",
      "no_triggers_reactive": "No triggers — agent wakes on incoming messages only",
      "cron": {
        "name": "Name",
        "name_required": "Name is required",
        "expr": "Cron expression",
        "expr_hint": "5-field standard cron (min hr dom mon dow)",
        "expr_required": "Cron expression is required",
        "tz": "Timezone (optional)",
        "message": "Message",
        "message_placeholder": "Message sent to the agent when the cron fires…",
        "enabled": "Enabled",
        "create": "Create cron job",
        "edit": "Edit cron job",
        "created": "Cron job created",
        "updated": "Cron job updated",
        "deleted": "Cron job deleted",
        "no_id": "Cron job has no id",
        "edit_disabled_non_cron": "This schedule uses 'every' or 'at' — edit it from agent.toml to avoid silent conversion to a cron expression."
      },
      "trigger": {
        "pattern": "Event pattern",
        "invalid_pattern": "Invalid trigger pattern JSON",
        "prompt": "Prompt template",
        "prompt_placeholder": "Prompt sent to the agent when the event fires…",
        "max_fires": "Max fires (0 = unlimited)",
        "cooldown": "Cooldown (seconds, blank = none)",
        "session_mode": "Session mode (blank = agent default)",
        "create": "Create trigger",
        "edit": "Edit trigger",
        "created": "Trigger created",
        "updated": "Trigger updated",
        "deleted": "Trigger deleted"
      }
    }
  },
  "providers": {
    "title": "Providers",
    "subtitle": "Manage LLM API connections and health.",
    "configured_count": "{{configured}} / {{total}} Configured",
    "models": "Models",
    "latency": "Latency",
    "test_connection": "Test Connection",
    "analyzing": "Analyzing...",
    "reachable": "Reachable",
    "unreachable": "Unreachable",
    "not_checked": "Not checked",
    "configured": "Configured",
    "unconfigured": "Unconfigured",
    "online": "Online",
    "offline": "Offline",
    "require_config": "Requires Setup",
    "no_configured": "No configured providers",
    "no_unconfigured": "No unconfigured providers",
    "no_results": "No matching providers",
    "name": "Name",
    "test": "Test",
    "batch_test": "Batch Test",
    "select_all": "Select All",
    "health": "Health",
    "key_required": "Key Required",
    "details": "Details",
    "last_test": "Last Test",
    "error": "Error",
    "open_settings": "Open Settings",
    "filter_all": "All",
    "filter_reachable": "Reachable",
    "filter_unreachable": "Unreachable",
    "results": "results",
    "config": "Configure",
    "configure_provider": "Configure Provider",
    "key_saved": "API Key saved",
    "key_removed": "API Key removed",
    "key_placeholder": "Enter API key...",
    "key_placeholder_existing": "Enter new key to replace...",
    "optional": "optional",
    "remove_key": "Remove Key",
    "base_url": "Base URL",
    "base_url_hint": "Bare host:port URLs (e.g. http://192.168.1.10:11434) will get /v1 appended automatically for OpenAI-compatible endpoints.",
    "proxy_url": "Proxy URL",
    "proxy_url_placeholder": "http://proxy:8080 or socks5://proxy:1080",
    "api_key": "API Key",
    "set_as_default": "Set as Default",
    "default_set": "Default provider updated",
    "auto_select_model": "Auto-select best model",
    "model_name_placeholder": "e.g. llama3.2, qwen2.5",
    "is_default": "Default",
    "add": "Add Provider",
    "delete_confirm_title": "Remove Provider Key",
    "delete_confirm_message": "Are you sure you want to remove the API key for this provider? The provider will become unconfigured.",
    "help": "Providers are the LLM vendor connections (OpenAI, Anthropic, Gemini, Groq, …) — credentials, base URL, and health state. The model catalogue derives availability from this page, and every LLM call routes through a configured provider.\n\nHow to use this page:\n\n1. Add or edit. \"Add\" creates a new provider connection — pick the kind, paste the API key, set base URL if you're hitting a self-hosted / proxy endpoint. Edit updates an existing one.\n\n2. Test connectivity. \"Batch test\" pings every configured provider; per-row test does one. Successful test means the credentials authenticate and the endpoint is reachable.\n\n3. Auto-select model. After test, \"Auto-select model\" picks a sane default model for that provider so newly created agents have something to use.\n\n4. Watch health. Status badge tells you whether the provider is healthy, throttled, or auth-failed.\n\nTypical scenarios:\n\n  · Bringing a new provider online — paste key, test, auto-select, done.\n  · Switching from cloud Anthropic to a local proxy by editing the base URL.\n  · Diagnosing \"why aren't any models available\" — usually a missing or expired key here.\n\nThings to know:\n\n  · 401 / 403 from a provider is treated as \"reachable, auth-failed\" — different from \"unreachable\" so test results are accurate.\n  · Keys are stored in config; treat the host as a secret store.\n  · Removing a provider doesn't delete agents that pointed at it — but their model picks become unavailable until re-pointed.",
    "wizard_step_basics": "Basics",
    "wizard_step_advanced": "Advanced",
    "wizard_step_models": "Models",
    "wizard_id_label": "Provider ID",
    "wizard_id_placeholder": "my-provider",
    "wizard_id_hint": "Lowercase with hyphens. Used as the unique identifier.",
    "wizard_base_url_label": "Base URL",
    "wizard_base_url_placeholder": "https://api.example.com/v1",
    "wizard_api_key_label": "API Key",
    "wizard_api_key_placeholder": "sk-...",
    "wizard_api_key_hint": "Leave empty for local providers that don't require a key.",
    "wizard_display_name_label": "Display Name",
    "wizard_api_key_env_label": "API Key Env Var",
    "wizard_key_required_label": "Requires API Key",
    "wizard_advanced_hint": "These values are auto-derived from the Provider ID. Override only if needed.",
    "wizard_models_hint": "Optionally add models now, or add them later.",
    "wizard_model_id": "Model ID",
    "wizard_model_name": "Display Name",
    "wizard_model_tier": "Tier",
    "wizard_model_context": "Context Window",
    "wizard_model_max_output": "Max Output Tokens",
    "wizard_model_input_cost": "Input Cost / 1M tokens",
    "wizard_model_output_cost": "Output Cost / 1M tokens",
    "wizard_next": "Next",
    "wizard_back": "Back",
    "wizard_skip_create": "Skip & Create",
    "wizard_create": "Create Provider",
    "wizard_creating": "Creating...",
    "wizard_id_required": "Provider ID is required",
    "wizard_base_url_required": "Base URL is required",
    "wizard_auto_derived": "Auto-derived",
    "wizard_env_var": "Env Var",
    "provider_models": "Models",
    "no_models_for_provider": "No models registered",
    "remove_key_confirm_title": "Remove API Key",
    "remove_key_confirm_message": "This will remove the stored API key and move the provider back to unconfigured.",
    "all_configured": "All providers configured",
    "empty_title": "No providers configured yet",
    "empty_body": "Connect OpenAI, Anthropic, Gemini, Groq, or any other LLM provider so agents can route prompts and consume models.",
    "connect_first": "Connect a provider",
    "picker_title": "Add provider",
    "create_custom": "Create custom provider"
  },
  "channels": {
    "add": "Add",
    "all_configured": "All channels configured",
    "category": "Category",
    "config": "Configure",
    "config_template_summary": "Or paste this into config.toml by hand",
    "configured_count": "{{count}} Active Connectors",
    "connect_first": "Connect a channel",
    "empty_body": "Connect Slack, Discord, email, SMS, or any of the bundled bridges so agents can post and receive messages.",
    "empty_title": "No channels yet",
    "has_token": "Has Token",
    "help": "Channels are the inbound/outbound bridges that let humans talk to your agents — Slack, Discord, Telegram, email, webhooks, and more. Each channel has its own adapter; configuring a channel here wires that adapter to a credential and turns it on.\n\nHow to use this page:\n\n1. Browse the catalogue. Cards show every channel adapter the runtime supports, with a \"Configured\" / \"Not configured\" badge and a difficulty label.\n\n2. Configure. Click \"Configure\" on a channel; fill in the required fields (token, app id, webhook URL, …). Save persists to config and reloads the adapter live — no daemon restart needed.\n\n3. QR login. Some adapters (e.g. WhatsApp/Web) use a QR-code session login instead of a token. Click \"QR login\" and scan with the phone app.\n\n4. Verify. After save, the card flips to \"Configured\" and the adapter shows up on Comms with live event flow.\n\nTypical scenarios:\n\n  · Plugging an agent into a team Slack so anyone can DM it.\n  · Wiring an inbound webhook that fires the agent on GitHub events.\n  · Running multiple Telegram bots from one instance, each routed to a different agent via channel bindings.\n\nThings to know:\n\n  · Channel binding (which agent answers on which channel) is set on the agent's manifest — this page only owns the adapter credentials.\n  · Some channels need fields that are platform secrets — they're stored in the local config and are admin-only.\n  · Reload re-parses the channel config without restarting the daemon. If reload fails, the previous config keeps running.",
    "msgs_24h": "msgs/24h",
    "name": "Name",
    "no_configured": "No configured channels",
    "no_results": "No matching channels",
    "picker_title": "Add channel",
    "reload": "Reload",
    "reload_success": "Channels reloaded",
    "required_fields": "Required Fields",
    "results": "results",
    "saved": "Saved",
    "saved_restart_required": "Saved — restart daemon to apply",
    "secret_set_placeholder": "•••• (set — leave blank to keep)",
    "select_all": "Select All",
    "shadowed_secrets_warning": "Warning: these tokens are shadowed by shell environment variables and won't take effect until you unset them and restart: {{keys}}",
    "subtitle": "Messaging adapters and integration gateways.",
    "title": "Channels"
  },
  "skills": {
    "title": "Skills",
    "subtitle": "Atomic capabilities that extend agent reasoning.",
    "tools": "Tools",
    "author": "Author",
    "uninstall": "Uninstall",
    "no_skills": "No skills available.",
    "uninstall_confirm_title": "Uninstall Skill",
    "uninstall_confirm": "Are you sure you want to uninstall \"{{name}}\"? This action cannot be undone.",
    "installed": "Installed",
    "pending_tab": "Pending",
    "marketplace": "Marketplace",
    "install": "Install",
    "installing": "Installing...",
    "installed_count": "{{count}} Installed",
    "browse": "Browse",
    "browse_registry": "Registry",
    "source_fanghub": "FangHub",
    "source_clawhub": "ClawHub",
    "source_clawhub_cn": "ClawHub CN",
    "source_skillhub": "SkillHub",
    "sort_trending": "Trending",
    "sort_downloads": "Downloads",
    "sort_stars": "Stars",
    "sort_updated": "Updated",
    "sort_rating": "Rating",
    "no_results": "No skills found",
    "rate_limited": "Rate Limited",
    "rate_limited_desc": "ClawHub API rate limit exceeded. Please try again later.",
    "load_error": "Failed to load",
    "search_placeholder": "Search skills (e.g. python, web, ai...)",
    "stars_count": "stars",
    "downloads_count": "downloads",
    "install_timeout": "Installation timed out",
    "help": "Skills are atomic capabilities — single-purpose prompt + tool snippets that an agent can pick up to extend its reasoning (e.g. \"summarise a long doc\", \"extract entities\", \"do a Wikipedia lookup\"). Different from hands (managed multi-tool bundles) and plugins (raw code): a skill is a small, declarative unit, often hot-edited.\n\nHow to use this page:\n\n1. Browse. Filter by source (built-in, marketplace, custom) and category. Each card shows author, downloads, description.\n\n2. Install / create. Marketplace skills install with one click. \"Create\" lets you write a custom skill in-place — name, description, prompt; the editor enforces sane limits.\n\n3. Evolve. Each skill has an evolution history — versions, changelogs, attached files. Use it to iterate on the prompt or attach reference docs without losing the prior version.\n\n4. Browse the registry. The registry tab shows the wider public catalogue you can pull from.\n\nTypical scenarios:\n\n  · Installing a community skill that does a tricky thing well, instead of writing it yourself.\n  · Forking a skill, editing the prompt for your domain, keeping both versions via evolution.\n  · Building a small library of internal skills your agents share.\n\nThings to know:\n\n  · Skill names must pass validation (no path tricks, length cap). Conflicts surface as \"name conflict\" errors.\n  · Prompt size is capped — large reference content goes in evolution-attached files, not the prompt body.\n  · Security-blocked errors mean a skill tried to do something the runtime forbids (e.g. write outside its sandbox).",
    "skillhub": "SkillHub",
    "skillhub_search_placeholder": "Search SkillHub...",
    "skillhub_rate_limited_desc": "SkillHub rate limit reached. Please try again later.",
    "hub_unreachable": "unreachable",
    "hub_checking": "checking…",
    "all_hubs": "All hubs",
    "builtin": "FangHub",
    "official": "Official",
    "install_to": "Install to",
    "global": "Global (all agents)",
    "cat_coding": "Coding",
    "cat_git": "Git",
    "cat_web": "Web",
    "cat_devops": "DevOps",
    "cat_browser": "Browser",
    "cat_ai": "AI",
    "cat_data": "Data",
    "cat_productivity": "Productivity",
    "cat_security": "Security",
    "cat_cli": "CLI",
    "reload_from_disk": "Reload",
    "reloaded": "Rescanned skills directory ({{count}} loaded)",
    "evo_create": "Create Skill",
    "evo_created": "Skill created successfully",
    "evo_create_title": "Create Skill",
    "evo_name_hint": "Lowercase, hyphens allowed (e.g., csv-analysis)",
    "evo_desc_placeholder": "What this skill teaches agents to do",
    "evo_prompt_context": "Prompt Context (Markdown)",
    "evo_prompt_placeholder": "# Skill Instructions\n\nMarkdown instructions injected into the system prompt...",
    "evo_tags": "Tags (comma-separated)",
    "evo_fill_required": "Name and description are required",
    "evo_update": "Update",
    "evo_updated": "Skill updated",
    "evo_update_title": "Update {{name}}",
    "evo_patch": "Patch",
    "evo_patched": "Skill patched",
    "evo_patch_title": "Patch {{name}}",
    "evo_patch_old": "Find",
    "evo_patch_new": "Replace with",
    "evo_replace_all": "Replace all occurrences",
    "evo_changelog_placeholder": "What changed and why",
    "evo_rollback": "Rollback",
    "evo_rollback_confirm": "Roll back to the previous version? This cannot be undone unless you patch again.",
    "evo_rolled_back": "Skill rolled back",
    "evo_no_rollback": "No prior version to roll back to",
    "evo_delete": "Delete",
    "evo_delete_title": "Delete this agent-evolved skill",
    "evo_delete_confirm": "Permanently delete {{name}}? This cannot be undone.",
    "evo_deleted": "Skill deleted",
    "evo_add_file": "Add File",
    "evo_upload": "Upload",
    "evo_upload_title": "Add file to {{name}}",
    "evo_folder": "Folder",
    "evo_filename": "Filename",
    "evo_content": "Content",
    "evo_content_placeholder": "Paste file content or load from disk below",
    "evo_load_from_disk": "Load from disk",
    "evo_file_uploaded": "File uploaded",
    "evo_file_too_large": "File exceeds 1 MiB limit",
    "evo_files": "Supporting Files",
    "evo_view_file": "View file",
    "evo_file_truncated": "File truncated to 256 KiB preview",
    "evo_remove_file": "Remove file",
    "evo_remove_file_confirm": "Remove {{path}}?",
    "evo_file_removed": "File removed",
    "evo_history": "Version History",
    "evo_uses": "Uses",
    "evo_evolutions": "Evolutions",
    "evo_prompt_size": "Prompt context",
    "evo_not_found": "Skill not found",
    "err_name_conflict": "A skill with this name already exists. Please choose a different name.",
    "err_desc_too_long": "Description is too long (max 1024 characters).",
    "err_prompt_too_large": "Prompt context is too large (max 160,000 characters).",
    "err_security_blocked": "Content was blocked by security scan. Please remove potentially dangerous patterns.",
    "err_invalid_name": "Invalid skill name. Use lowercase letters, numbers, hyphens, and underscores only.",
    "err_create_failed": "Failed to create skill. Please try again.",
    "outputs": "Skill Outputs",
    "evo_load_failed": "Failed to load file",
    "evo_action_failed": "Action failed",
    "evo_delete_failed": "Delete failed",
    "reload_failed": "Reload failed"
  },
  "hands": {
    "title": "Hands",
    "subtitle": "Autonomous capability packages.",
    "view_manifest": "View HAND.toml",
    "manifest_title": "HAND.toml — {{name}}",
    "manifest_error": "Failed to load HAND.toml",
    "available": "Available Hands",
    "instances": "Active Instances",
    "running_now": "Running Now",
    "activate": "Activate",
    "deactivate": "Deactivate",
    "orchestration": "Capability Orchestration",
    "active_label": "active",
    "total_label": "total",
    "search_placeholder": "Search hands...",
    "ready": "Ready",
    "degraded": "Degraded",
    "no_matching_hint": "Try a different search term or clear the active filters.",
    "clear_filters": "Clear filters",
    "missing_req": "Missing Requirements",
    "instance": "Instance",
    "agent": "Agent",
    "activated_at": "Activated",
    "paused": "Paused",
    "pause": "Pause",
    "resume": "Resume",
    "inactive_label": "Inactive",
    "metrics": "Metrics",
    "metrics_no_data": "No metrics data yet.",
    "settings": "Settings",
    "settings_empty": "No settings available.",
    "tab_schedules": "Schedules",
    "new_schedule": "New schedule",
    "schedule_name_placeholder": "e.g. Daily status check",
    "schedule_message_placeholder": "What should the hand do when this fires?",
    "schedule_created": "Schedule created",
    "configure_delivery_targets": "Configure delivery targets →",
    "requirements": "Requirements",
    "tools": "Tools",
    "cat_content": "Content",
    "cat_productivity": "Productivity",
    "cat_data": "Data",
    "cat_development": "Development",
    "cat_communication": "Communication",
    "help": "Hands are autonomous capability packages — bundled tool sets + glue logic that an agent can pick up to gain a new ability (e.g. \"browse the web\", \"operate Telegram bot\", \"run sandboxed shell\"). Unlike skills (single capabilities) or plugins (raw extensions), a hand is a cohesive, lifecycle-managed bundle.\n\nHow to use this page:\n\n1. Browse. Each card shows a hand's name, description, status (active / paused / degraded), and required dependencies.\n\n2. Activate. \"Activate\" enables the hand — its tools become available to agents that ask for them. \"Deactivate\" turns it off cleanly.\n\n3. Pause / resume. Pause keeps state but stops the hand from accepting work. Useful when debugging or quota-crunching without losing config. Resume brings it back.\n\n4. Configure delivery. \"Configure delivery targets\" routes hand outputs to specific channels / agents — the orchestration knob between hand and the rest of the system.\n\nWhen to use it (vs. Skills / Plugins / MCP):\n\n  · Skills — atomic capability units, smaller-grained.\n  · Plugins — raw runtime extensions you wrote or installed.\n  · Hands — opinionated, lifecycle-managed capability bundles.\n  · MCP — external tool servers reached over a protocol.\n\nTypical scenarios:\n\n  · Activating a \"browser\" hand so an agent can scrape and summarise pages.\n  · Pausing a noisy hand during a quiet period without unconfiguring it.\n  · Diagnosing a hand stuck in \"degraded\" by reading its manifest error.\n\nThings to know:\n\n  · \"Degraded\" usually means a missing dependency or a failing health-check — the manifest error message points at the cause.\n  · Deactivating a hand mid-call is graceful: in-flight invocations finish, no new ones start.",
    "settings_activate_first": "Activate this hand first to edit its settings.",
    "settings_default": "default",
    "settings_save": "Save settings",
    "settings_saved": "Saved",
    "uninstall": "Uninstall this hand",
    "uninstall_confirm": "Uninstall this hand? Its HAND.toml and workspace files will be deleted. This cannot be undone."
  },
  "analytics": {
    "title": "Analytics",
    "subtitle": "Usage statistics and performance telemetry.",
    "intelligence": "System Intelligence",
    "compute": "Compute Usage",
    "compute_desc": "Resources consumed by providers.",
    "runtime": "Runtime Status",
    "runtime_desc": "Core system execution metrics.",
    "active_agents": "Active Agents",
    "configured_channels": "Configured Channels",
    "available_skills": "Available Skills",
    "health_checks": "Health Checks",
    "advanced": "Advanced Metrics",
    "advanced_desc": "Detailed analysis coming soon.",
    "usage_by_model": "Cost by Model",
    "usage_by_model_desc": "Token spend breakdown per model.",
    "daily_trend": "Daily Cost Trend",
    "daily_trend_desc": "Cost over the last 14 days.",
    "today_cost": "Today's Cost",
    "total_calls": "Total Calls",
    "total_tokens_label": "Total Tokens",
    "budget_title": "Budget Limits",
    "budget_desc": "Set spending caps to control costs.",
    "hourly_limit": "Hourly Limit",
    "daily_limit": "Daily Limit",
    "monthly_limit": "Monthly Limit",
    "token_limit": "Tokens/Hour",
    "alert_threshold": "Alert Threshold",
    "budget_saved": "Budget limits updated.",
    "usage_summary": "Usage Overview",
    "usage_summary_desc": "API call consumption statistics.",
    "total_requests": "Total Requests",
    "total_tokens": "Total Tokens",
    "total_cost": "Total Cost",
    "avg_latency": "Avg Latency",
    "usage_by_agent": "Usage by Agent",
    "usage_by_agent_desc": "Consumption ranking by agent.",
    "no_agent_data": "No agent usage data yet",
    "no_model_data": "No model usage data yet",
    "no_trend_data": "No trend data available yet",
    "cost_per_call": "Cost per Call",
    "cheapest_call": "Cheapest/Call",
    "avg_cost_per_call": "Avg Cost/Call",
    "help": "Analytics aggregates LLM call cost, latency, and throughput across every agent and provider this instance has used. The numbers come from the metering layer that records every model call — same source as the per-agent budget figures, just sliced for charting.\n\nHow to use this page:\n\n1. Pick a window. Use the time-range selector to focus on today, this week, this month, or a custom range. All charts and tables re-aggregate.\n\n2. Read the headline metrics. Total cost, total calls, average cost-per-call, average latency — these tell you whether spend is healthy at a glance.\n\n3. Drill in. The \"Model performance\" table breaks down latency / cost / call count per model so you can see which model is paying for itself. The daily-trend chart shows whether usage is climbing.\n\n4. Set guardrails. The budget panel lets you set hourly / daily / monthly limits and an alert threshold. Crossing the alert threshold surfaces in Approvals.\n\nTypical scenarios:\n\n  · Catching a runaway agent before the monthly bill arrives — daily trend spike + the per-agent ranking on Budget tells you who.\n  · Comparing latency between providers when picking a default model.\n  · Exporting CSV for finance / reporting.\n\nThings to know:\n\n  · Numbers update as calls land — there's no hourly rollup delay, but very recent calls (last few seconds) may not be counted yet.\n  · Cost is computed from the model catalogue's published prices; if a provider's pricing changes, update the model entry on the Models page.\n  · Budget limits set here are global; per-agent caps live on the agent's own page.",
    "cost": "Cost",
    "avg": "Avg",
    "min": "Min",
    "max": "Max",
    "cost_per_call_label": "Cost/Call",
    "calls": "Calls",
    "cost_call": "Cost/Call",
    "export_csv": "Export CSV",
    "fastest_model": "Fastest Model",
    "latency_by_model": "Latency by Model",
    "min_max": "Min / Max",
    "model": "Model",
    "model_performance_table": "Model Performance",
    "tokens": "Tokens"
  },
  "memory": {
    "title": "Memory",
    "subtitle": "Persistent vector storage for agent context.",
    "cognitive_layer": "Cognitive Layer",
    "objects_stored": "{{count}} Objects Stored",
    "add_memory": "Add Memory",
    "edit_memory": "Edit Memory",
    "content": "Content",
    "content_placeholder": "Enter memory content...",
    "level": "Level",
    "agent_id": "Agent ID",
    "agent_optional": "Optional",
    "episodic": "Episodic",
    "semantic": "Semantic",
    "working": "Working",
    "total_memories": "Total Memories",
    "importance": "Importance",
    "cleanup": "Cleanup",
    "decay": "Decay",
    "add": "Add",
    "filter_all": "All",
    "showing": "Showing {{count}} / {{total}}",
    "no_memories": "No memories yet",
    "created": "Created",
    "config_title": "Memory Configuration",
    "config_desc": "Changes are written to config.toml. Restart required for full effect.",
    "embedding_provider": "Embedding",
    "extraction_model": "Extraction",
    "proactive": "Proactive",
    "proactive_enabled": "Enabled",
    "auto_memorize": "Auto Memorize",
    "auto_retrieve": "Auto Retrieve",
    "help": "Memory is the agent's long-term store — embedded vectors plus structured records that the agent retrieves at recall time to keep context across sessions. This page lets you browse, search, edit, and seed memories, and configure the embedding / retrieval behaviour.\n\nHow to use this page:\n\n1. Browse / search. The list shows recent memories with access count and metadata. Search runs vector similarity (when an embedding provider is configured) or text fallback.\n\n2. Add. \"Add memory\" lets you seed a fact manually — pick scope (global / per-agent), fill content, save. Useful for hand-curated knowledge.\n\n3. Edit / delete. Click a row to inspect, edit, or delete. Edits re-embed automatically.\n\n4. Configure. The settings panel toggles auto-memorize (agent writes new memories as it runs), auto-retrieve (memories are injected into context), and chooses the embedding provider / API key.\n\nTypical scenarios:\n\n  · Seeding \"always reply in Chinese to user @evan\" once, instead of repeating it in the system prompt.\n  · Inspecting what an agent has actually remembered and pruning low-value rows.\n  · Switching embedding providers when costs / quality change.\n\nThings to know:\n\n  · Storage is SQLite in `~/.librefang/`. Backups live there too.\n  · Per-agent memories don't bleed across agents; global ones are visible to all.\n  · Disabling auto-retrieve doesn't delete memories — it just stops them being injected. You can still query manually.",
    "access_count": "Accessed",
    "category": "Category",
    "cleanup_success": "Cleanup complete",
    "delete_success": "Memory deleted",
    "last_access": "Last access",
    "embedding_section": "Embedding",
    "provider": "Provider",
    "auto_detect": "Auto-detect",
    "provider_openai": "OpenAI",
    "provider_ollama": "Ollama",
    "provider_vllm": "vLLM",
    "provider_lmstudio": "LM Studio",
    "provider_gemini": "Gemini",
    "provider_minimax": "MiniMax",
    "model": "Model",
    "api_key_env": "API Key Env",
    "api_key_env_hint": "Local providers (Ollama / vLLM / LM Studio) typically don't need a key — leave blank.",
    "proactive_memory": "Proactive Memory",
    "extraction_model_label": "Extraction Model",
    "max_retrieve": "Max Retrieve",
    "decay_rate": "Decay Rate",
    "auto": "auto",
    "agent_label": "Agent:",
    "user": "User",
    "session": "Session",
    "agent": "Agent",
    "tab_aria_label": "Memory views",
    "tab_records": "Records",
    "tab_kv": "KV",
    "tab_dreams": "Auto-Dream",
    "tab_health": "Health",
    "scope_agent_label": "Agent",
    "scope_all_label": "Scope",
    "rail_title": "Agent scope",
    "rail_filter_placeholder": "Filter agents",
    "rail_all_agents": "All agents",
    "rail_records_short": "mem",
    "rail_kv_short": "KV",
    "rail_no_match": "No matching agents.",
    "auto_dream_on_badge": "Auto-Dream on",
    "auto_dream_off_badge": "Auto-Dream off",
    "auto_dream_desc_inline": "Periodic memory consolidation per agent. Manifest override > global default; configure global in config.toml under [auto_dream].",
    "kv_label_short": "KV pairs",
    "kv_no_agents": "No agents available",
    "kv_agent_missing": "Selected agent has no KV data yet",
    "kv_key": "Key",
    "kv_value": "Value",
    "kv_source": "Source",
    "kv_empty": "No KV entries",
    "dream_no_status": "No dream status yet — the scheduler hasn't registered this agent.",
    "dream_agent_missing": "Selected agent has no dream status yet",
    "records_filtered_to_agent": "filtered to this agent",
    "embedding_model_default": "Auto / provider default",
    "extraction_model_default": "Use kernel default",
    "extraction_model_placeholder": "e.g. openai/gpt-4o-mini",
    "custom_model_option": "Custom…",
    "decay_rate_hint": "Per-day decay applied to memory confidence. Lower = memories age more slowly.",
    "decay_rate_invalid": "Must be a number between 0 and 1.",
    "max_retrieve_invalid": "Must be an integer between 1 and 50.",
    "config_invalid_stored": "Stored config has out-of-range numeric values. Fix the highlighted field(s) below to enable Save.",
    "delete_confirm_title": "Delete Memory",
    "delete_confirm_message": "This memory will be permanently deleted.",
    "proactive_disabled_notice": "Proactive memory is disabled in config — no records to show. KV memory and Auto-Dream still work.",
    "health_embedding_title": "Embedding backbone",
    "health_embedding_ok": "Reachable",
    "health_embedding_down": "Not reachable",
    "health_provider": "Provider",
    "health_model": "Model",
    "health_api_key_env": "API key env",
    "health_unset": "unset",
    "health_embed_hint_ok": "Liveness probe succeeded — the configured embedding backend responded to a test call.",
    "health_embed_hint_fail": "Liveness probe failed. Memory writes will skip vector indexing until the provider is reachable. Check API key, base URL, and that the local server (Ollama / vLLM / LM Studio) is running.",
    "health_proactive_title": "Proactive memory",
    "health_proactive_on": "Enabled",
    "health_proactive_off": "Disabled",
    "health_extraction_model": "Extraction model",
    "health_use_default": "kernel default",
    "health_auto_memorize": "Auto memorize",
    "health_auto_retrieve": "Auto retrieve",
    "health_decay_rate": "Decay rate",
    "health_dream_title": "Auto-Dream",
    "health_dream_with_errors": "Running with errors",
    "health_dream_on": "Running",
    "health_dream_off": "Disabled",
    "health_dream_enrolled": "Agents enrolled",
    "health_dream_last": "Last successful consolidation",
    "health_dream_failed": "Enrolled agents with broken last run",
    "health_dream_warn": "One or more enrolled agents' last dream ended in failure or abort. Open the Auto-Dream tab and check the per-agent error message.",
    "health_actions_title": "Tune behaviour",
    "health_actions_desc": "All knobs above live in config.toml. The Settings drawer mirrors them with validation and dropdowns.",
    "health_open_config": "Open configuration"
  },
  "comms": {
    "bus": "Communication Bus",
    "subtitle": "Real-time message traffic and connectivity.",
    "active_channels": "Channels",
    "active_channels_description": "Connectivity status of adapters.",
    "unconfigured": "Unconfigured",
    "health_description": "Sub-system checks.",
    "awaiting_telemetry": "Awaiting telemetry...",
    "topology": "Network Topology",
    "topology_description": "High-performance event bus coordination.",
    "no_channels": "No communication channels discovered.",
    "total_channels": "Total Channels",
    "connected": "Connected",
    "events_today": "Events Today",
    "uptime": "Uptime",
    "events": "Events",
    "events_desc": "Real-time message events.",
    "connections": "Connections",
    "help": "Comms is the live monitor for the messaging bus. While Channels owns configuration, Comms shows what's actually flowing — connected adapters, recent send/receive events, the agent ↔ channel topology, and basic health.\n\nHow to use this page:\n\n1. Health row. Active channels, total events today, daemon uptime — quick \"is the bus alive\" check.\n\n2. Event timeline. Latest send / receive / error events with source, kind, and timestamp. Search to filter by channel, agent, or text.\n\n3. Topology. Visualises which agents are reachable on which channels right now.\n\nTypical scenarios:\n\n  · \"User says the Telegram bot didn't reply\" — check the timeline for a matching receive event and whether a send went out.\n  · Catching a channel that silently dropped its connection (no heartbeat events).\n  · Watching a fresh deploy land — events should resume within seconds.\n\nThings to know:\n\n  · The event stream is in-memory and bounded — older events fall off. For deep history, the audit trail and per-channel logs are authoritative.\n  · \"Online\" here means the adapter is connected; it doesn't guarantee the remote service (Slack, Telegram, …) is healthy upstream."
  },
  "canvas": {
    "title": "Designer",
    "subtitle": "Design visual logic flows for autonomous agent behavior.",
    "node_library": "Node Library",
    "triggers": "Triggers",
    "logic": "Logic",
    "actions": "Actions",
    "clear_confirm": "Are you sure you want to clear the canvas?",
    "no_agent_steps": "No nodes with assigned agents. Click a node to assign an agent.",
    "name_required": "Please enter a workflow name.",
    "node_config": "Node Config",
    "node_label": "Label",
    "node_desc": "Description",
    "assign_agent": "Assign Agent",
    "no_agent": "-- No Agent --",
    "agent_steps": "agent steps",
    "run_result": "Run Result",
    "run_input_title": "Run Workflow",
    "run_input_hint": "Enter input for the first step (passed as {{input}}). Leave empty to run without input.",
    "run_input_placeholder": "e.g. Translate this text...",
    "run_now": "Run",
    "to_run": "to run",
    "step_mode": "Execution Mode",
    "mode_sequential": "Sequential",
    "mode_fan_out": "Parallel (Fan Out)",
    "mode_collect": "Collect (Merge Parallel)",
    "mode_conditional": "Conditional",
    "mode_loop": "Loop",
    "condition_text": "Condition Text",
    "condition_placeholder": "Execute if prev output contains...",
    "loop_until": "Stop When Output Contains",
    "loop_until_placeholder": "e.g. DONE",
    "loop_max": "Max Iterations",
    "error_mode": "Error Handling",
    "error_fail": "Stop on Error",
    "error_skip": "Skip on Error",
    "error_retry": "Retry on Error",
    "max_retries": "Max Retries",
    "timeout": "Timeout (seconds)",
    "output_var": "Output Variable",
    "output_var_hint": "(use {{name}} in later steps)",
    "example_placeholder": "e.g. research_result",
    "create_group": "Group Selected",
    "new_group": "Group",
    "unsaved": "Unsaved changes",
    "empty_title": "Empty Canvas",
    "empty_hint": "Add nodes from the sidebar or right-click to add",
    "collapse_sidebar": "Collapse",
    "expand_sidebar": "Expand",
    "ctx_edit": "Edit Node",
    "ctx_copy": "Copy",
    "ctx_duplicate": "Duplicate",
    "ctx_add_agent": "Add Agent Node",
    "ctx_paste": "Paste",
    "ctx_select_all": "Select All",
    "ctx_auto_layout": "Auto Layout",
    "ctx_delete_connection": "Delete Connection",
    "click_to_assign": "Click to assign agent",
    "saved": "Saved",
    "exported": "Exported",
    "imported": "Imported",
    "import_error": "Invalid workflow file",
    "shortcuts_title": "Keyboard Shortcuts",
    "sc_undo": "Undo",
    "sc_redo": "Redo",
    "sc_copy": "Copy",
    "sc_paste": "Paste",
    "sc_duplicate": "Duplicate",
    "sc_select_all": "Select All",
    "sc_group": "Group",
    "sc_ungroup": "Ungroup",
    "sc_fit_view": "Fit View",
    "sc_export": "Export JSON",
    "sc_import": "Import JSON",
    "sc_delete": "Delete",
    "sc_pan": "Pan Canvas",
    "sc_select": "Box Select",
    "sc_context": "Context Menu",
    "sc_help": "Toggle Help",
    "node_types": {
      "start": "Start",
      "start_desc": "Workflow entry point",
      "end": "End",
      "end_desc": "Workflow termination",
      "schedule": "Schedule",
      "schedule_desc": "Time-based trigger",
      "webhook": "Webhook",
      "webhook_desc": "HTTP webhook trigger",
      "channel": "Channel",
      "channel_desc": "Send to channel",
      "condition": "Condition",
      "condition_desc": "Branch logic",
      "loop": "Loop",
      "loop_desc": "Repeat actions",
      "parallel": "Parallel",
      "parallel_desc": "Parallel execution",
      "wait": "Wait",
      "wait_desc": "Delay/wait",
      "respond": "Respond",
      "respond_desc": "Send response",
      "collect": "Collect",
      "collect_desc": "Merge parallel results",
      "agent": "Agent",
      "agent_desc": "Run agent task"
    },
    "nodes": {
      "start": "Start",
      "start_desc": "Workflow entry point",
      "end": "End",
      "end_desc": "Workflow termination",
      "schedule": "Schedule",
      "schedule_desc": "Time-based trigger",
      "webhook": "Webhook",
      "webhook_desc": "HTTP webhook trigger",
      "channel": "Channel",
      "channel_desc": "Send to channel",
      "condition": "Condition",
      "condition_desc": "Branch logic",
      "loop": "Loop",
      "loop_desc": "Repeat actions",
      "parallel": "Parallel",
      "parallel_desc": "Parallel execution",
      "wait": "Wait",
      "wait_desc": "Delay/wait",
      "collect": "Collect",
      "collect_desc": "Merge parallel results",
      "respond": "Respond",
      "respond_desc": "Send response",
      "agent": "Agent",
      "agent_desc": "Run agent task"
    },
    "ungroup": "Ungroup",
    "delete_group": "Delete group and children",
    "group": "Group",
    "fit_view": "Fit View (Cmd+1)",
    "export": "Export (Cmd+E)",
    "import": "Import (Cmd+I)",
    "shortcuts": "Shortcuts (?)",
    "dry_run_hint": "Dry Run — validate without calling LLMs",
    "dry_run": "Dry Run",
    "dry_run_desc": "Validate agents and preview resolved prompts without calling any LLMs.",
    "validate": "Validate",
    "valid": "Valid",
    "issues_found": "Issues found",
    "skip": "skipped",
    "agent_not_found": "Agent not found",
    "resolved_prompt": "Resolved prompt:",
    "step_details": "Step details",
    "click_to_expand": "Click to expand",
    "fullscreen": "Fullscreen",
    "exit_fullscreen": "Exit fullscreen",
    "browse_templates": "Browse Templates",
    "depends_on": "Depends on",
    "depends_on_hint": "This node will only run after the selected nodes complete.",
    "load_error": "Failed to load data",
    "logic_actions": "Logic & Actions",
    "no_templates": "No templates available",
    "save_as_template": "Save as Template",
    "save_before_schedule": "Save the workflow before scheduling",
    "save_error": "Failed to create workflow",
    "save_first_to_template": "Save the workflow first before saving as template",
    "saved_as_template": "Saved as template",
    "scheduled": "Schedule created",
    "template_instantiate_error": "Failed to instantiate template",
    "template_load_error": "Failed to load template",
    "template_params": "Template Parameters",
    "template_search": "Search templates...",
    "use_template": "Use Template",
    "workflow_load_error": "Failed to load workflow"
  },
  "workflows": {
    "title": "Workflows",
    "subtitle": "Automation hub.",
    "all_workflows": "All Workflows",
    "run_workflow": "Run Workflow",
    "select_workflow": "Select workflow",
    "recent_runs": "Recent Runs",
    "no_runs": "No runs yet",
    "select_workflow_hint": "Select a workflow to view runs",
    "steps_count": "{{count}} steps",
    "nodes_unit": "nodes",
    "automation_hub": "Automation Hub",
    "templates": "Templates",
    "template_library": "Workflow Marketplace",
    "my_workflows": "My Workflows",
    "use_template": "Use Template",
    "create_blank": "Create Blank",
    "new_workflow": "New Workflow",
    "workflow_name": "Workflow Name",
    "description": "Description",
    "delete_confirm": "Are you sure you want to delete this workflow?",
    "open_workflows": "Workflow List",
    "untitled_workflow": "Untitled Workflow",
    "help": "Workflows are multi-step automations — a graph of nodes (LLM call, tool call, branch, …) the runtime executes top-to-bottom. Different from a single scheduler fire (one message in, one reply out): a workflow is the recipe with branches and intermediate steps. The visual canvas builds them; templates seed common shapes.\n\nHow to use this page:\n\n1. Create. \"Create blank\" opens an empty canvas, or pick a template (\"my workflows\" lists yours, \"all workflows\" shows shared).\n\n2. Edit nodes. Each node has its own context (`ctx_edit`) — edit prompts, tool refs, branch conditions. Connect nodes by dragging.\n\n3. Dry run. \"Dry run\" validates the workflow without calling LLMs — checks node wiring, missing references, agent IDs. Use it before a live run to catch config errors cheaply.\n\n4. Run now. Provide the run input, click \"Run now\"; output and resolved prompt show up; \"Run history\" tracks past runs.\n\nWhen to use it (vs. Scheduler / Goals):\n\n  · Scheduler — single-shot fire on a clock or event.\n  · Goals — long-lived intent, statefully tracked.\n  · Workflows — repeatable multi-step recipe with branching.\n\nTypical scenarios:\n\n  · \"Pull issue → summarise → ask agent for fix → post comment\" as one repeatable workflow.\n  · Templating a research pipeline that branches on whether a doc was found.\n  · Wiring a workflow as the target of a Scheduler cron — the cron fires the workflow.\n\nThings to know:\n\n  · Dry run catches missing-agent / unresolved-prompt errors without spending tokens — run it before saving big edits.\n  · Run history is per-workflow; outputs are kept until you delete the workflow.\n  · A failing run leaves a record with the failure point — read it before retrying.",
    "search_placeholder": "Search workflows...",
    "empty_title": "No workflows yet",
    "empty_desc": "Create your first workflow from a template or start from scratch.",
    "parameters": "Parameters",
    "additional_context_placeholder": "Additional context (optional)...",
    "template_details": {
      "content_pipeline": "Content Pipeline",
      "content_pipeline_desc": "Research → Write → Edit, produce polished articles",
      "translate_polish": "Translate & Polish",
      "translate_polish_desc": "Auto-detect language, translate and refine",
      "brainstorm": "Brainstorm",
      "brainstorm_desc": "Generate ideas → Evaluate → Create action plan",
      "weekly_report": "Weekly Report",
      "weekly_report_desc": "Turn messy notes into professional weekly reports"
    },
    "nodes": {
      "complete": "Complete",
      "complete_desc": "Workflow complete",
      "topic_input": "Topic Input",
      "topic_input_desc": "Enter your topic",
      "researcher": "Researcher",
      "researcher_desc": "Deep research on topic",
      "writer": "Writer",
      "writer_desc": "Write structured article",
      "editor": "Editor",
      "editor_desc": "Polish and finalize",
      "source_text": "Source Text",
      "source_text_desc": "Paste text to translate",
      "translator": "Translator",
      "translator_desc": "Auto-detect and translate",
      "reviewer": "Reviewer",
      "reviewer_desc": "Review translation quality",
      "challenge": "Challenge",
      "challenge_desc": "Describe your challenge",
      "idea_gen": "Idea Generator",
      "idea_gen_desc": "Generate 10 diverse ideas",
      "evaluator": "Evaluator",
      "evaluator_desc": "Score and rank ideas",
      "action_plan": "Action Plan",
      "action_plan_desc": "Create implementation plan",
      "work_notes": "Work Notes",
      "work_notes_desc": "Paste raw work notes",
      "organizer": "Organizer",
      "organizer_desc": "Categorize and structure",
      "report_writer": "Report Writer",
      "report_writer_desc": "Generate polished report"
    },
    "dry_run": "Dry Run",
    "dry_run_hint": "Dry Run — validate without calling LLMs",
    "dry_run_valid": "Valid — all agents resolved",
    "dry_run_warning": "Warning — some agents not found",
    "delete_failed": "Delete failed",
    "run_failed": "Run failed",
    "run_started": "Run started",
    "runs_label": "runs",
    "schedule_failed": "Schedule creation failed",
    "skip": "skip",
    "agent_not_found": "Agent not found",
    "resolved_prompt": "Resolved prompt:",
    "step_details": "Step details",
    "run_history": "Run History",
    "prompt_sent": "Prompt sent:",
    "output": "Output:",
    "generated_images": "Generated images:",
    "loading_details": "Loading details…"
  },
  "scheduler": {
    "title": "Scheduler",
    "subtitle": "Manage cron jobs and scheduled tasks.",
    "create_job": "Create Schedule",
    "pick_schedule": "Pick schedule",
    "job_name": "Job Name",
    "job_name_placeholder": "e.g. Weekly Health Check",
    "cron_exp": "Cron Expression",
    "target_agent": "Target Agent",
    "select_agent": "Select agent...",
    "active_schedules": "Schedules",
    "run_now": "Run Now",
    "event_triggers": "Event Triggers",
    "system_cron": "System Cron",
    "schedules": "schedules",
    "triggers_label": "triggers",
    "cron_jobs": "cron jobs",
    "no_schedules": "No schedules yet. Create one to automate agent tasks.",
    "target": "Target",
    "target_workflow": "Workflow",
    "select_workflow": "Select workflow...",
    "message": "Message",
    "message_placeholder": "Message to send to agent...",
    "every_minute": "Every minute",
    "every_n_minutes": "Every {{n}} min",
    "every_n_hours": "Every {{n}} hours",
    "weekly": "Weekly",
    "type_interval_min": "Min",
    "type_interval_hour": "Hour",
    "type_daily": "Daily",
    "type_weekday": "Wkday",
    "type_weekly": "Week",
    "type_monthly": "Month",
    "type_custom": "Cron",
    "every": "Every",
    "minutes": "minutes",
    "hours": "hours",
    "daily_at": "Daily",
    "weekdays_at": "Weekdays",
    "at": "At",
    "every_month_on": "Day",
    "day_suffix": "at",
    "field_min": "Min",
    "field_hour": "Hr",
    "field_day": "Day",
    "field_month": "Mon",
    "field_weekday": "Wk",
    "cron_invalid": "Invalid expression",
    "weekday_sun": "Sun",
    "weekday_mon": "Mon",
    "weekday_tue": "Tue",
    "weekday_wed": "Wed",
    "weekday_thu": "Thu",
    "weekday_fri": "Fri",
    "weekday_sat": "Sat",
    "weekday_short_mon": "M",
    "weekday_short_tue": "T",
    "weekday_short_wed": "W",
    "weekday_short_thu": "T",
    "weekday_short_fri": "F",
    "weekday_short_sat": "S",
    "weekday_short_sun": "S",
    "cron_every_n_min": "Every {{n}} min",
    "cron_every_n_hour": "Every {{n}}h",
    "cron_monthly": "{{dom}}th {{time}}",
    "cron_weekly": "{{day}} {{time}}",
    "cron_weekdays": "Weekdays {{time}}",
    "cron_daily": "Daily {{time}}",
    "help": "Scheduler runs agents on a clock or in response to events. Cron-style schedules fire at fixed intervals; event triggers fire when something happens elsewhere in the system. Each fire posts a message to its target agent (or workflow) just like a human would.\n\nHow to use this page:\n\n1. Create a schedule. \"Create job\" → pick agent or workflow, write a cron expression (or pick \"every minute\" / \"every N hours\" presets), set the message body. Save.\n\n2. Event triggers. The events tab lets you bind a trigger to an event source so the agent fires when that event happens, instead of on a clock.\n\n3. Configure delivery. \"Edit targets\" routes the schedule's output (agent reply) somewhere — a channel, another agent, a webhook.\n\n4. Manage. Toggle active / disabled, see \"next run\" timestamps, delete old jobs.\n\nWhen to use it (vs. Goals / Workflows):\n\n  · Goals — long-term intent, statefully tracked.\n  · Workflows — multi-step sequences, often graph-shaped.\n  · Scheduler — single-shot fires on a clock or event.\n\nTypical scenarios:\n\n  · Daily 9am \"summarise yesterday's incidents\" message to an ops agent.\n  · \"Every 15 minutes, check the queue and act if depth > N\".\n  · Event-driven fire when a webhook or another agent sends an event.\n\nThings to know:\n\n  · All cron fires for an agent share one session — they don't isolate per-fire. To get per-fire isolation, use `session_mode = \"new\"` AND don't rely on cron (use triggers via the dispatcher path).\n  · Cron fires are subject to per-agent concurrency caps. A long-running job will block the next fire.\n  · Cron expressions are second-precision when supported by the parser; check the next-run preview before saving.",
    "next_run": "Next",
    "save_success": "Schedule saved",
    "timezone": "Timezone",
    "weekdays": "Weekdays",
    "delivery": {
      "targets_label": "Delivery targets",
      "no_targets": "No fan-out targets. The legacy single delivery still applies.",
      "no_fanout": "no fan-out targets",
      "add_target": "Add target",
      "new_target": "New target",
      "type_channel": "Channel",
      "type_webhook": "Webhook",
      "type_local_file": "Local file",
      "type_email": "Email",
      "channel_type": "Channel type",
      "channel_type_helper": "Custom channel types are passed through as-is. Unknown values fail at delivery time with the list of configured adapters.",
      "recipient": "Recipient",
      "thread_id": "Thread ID (optional)",
      "account_id": "Account ID (optional)",
      "url": "Webhook URL",
      "auth_header": "Authorization header (optional)",
      "path": "File path",
      "append": "Append (uncheck to overwrite each run)",
      "email_to": "Recipient email",
      "subject_template": "Subject template (optional, {job} = job name)",
      "custom": "Custom…",
      "add": "Add target",
      "save": "Save targets",
      "saved": "Delivery targets updated",
      "edit_targets": "Edit targets",
      "edit_modal_title": "Edit delivery targets",
      "err_pick_type": "Pick a target type",
      "err_channel_type_required": "Channel type is required",
      "err_recipient_required": "Recipient is required",
      "err_url_required": "Webhook URL is required",
      "err_url_scheme": "Webhook URL must start with http:// or https://",
      "err_url_blocked_host": "Webhook host is not allowed (loopback / link-local / metadata service)",
      "err_path_required": "File path is required",
      "err_path_absolute": "File path must be workspace-relative, not absolute",
      "err_path_traversal": "File path must not contain '..'",
      "err_email_required": "Recipient email is required"
    }
  },
  "runtime": {
    "title": "Runtime",
    "subtitle": "Engine status and resource management.",
    "kernel": "Kernel Execution Environment",
    "environment": "Environment",
    "engine_version": "Engine Version",
    "system_uptime": "System Uptime",
    "engine": "Engine Info",
    "git_hash": "Git Commit",
    "build_time": "Build Time",
    "system": "System Status",
    "queue": "Task Queue",
    "pending_tasks": "Pending",
    "running_tasks": "Running",
    "completed_today": "Completed Today",
    "active_agents": "Active Agents",
    "status": "Status",
    "hostname": "Hostname",
    "platform": "Platform",
    "rust_version": "Rust Version",
    "config": "Runtime Config",
    "default_provider": "Default Provider",
    "default_model": "Default Model",
    "api_listen": "API Listen",
    "home_dir": "Home Directory",
    "log_level": "Log Level",
    "network_enabled": "Network",
    "memory_used": "Memory",
    "sessions": "Sessions",
    "health_checks": "Health Checks",
    "all_passed": "All Passed",
    "degraded": "Degraded",
    "queue_config": "Queue Config",
    "max_depth_agent": "Max Depth / Agent",
    "max_depth_global": "Max Depth Global",
    "task_ttl": "Task TTL",
    "lane": "Lane",
    "capacity": "Capacity",
    "no_lanes": "No queue lanes",
    "enabled": "Enabled",
    "disabled": "Disabled",
    "providers": "Providers",
    "channels": "Channels",
    "skills": "Skills",
    "workflows": "Workflows",
    "resources": "Resource Summary",
    "server_control": "Server Control",
    "reload_config": "Reload Config",
    "reload_success": "Config reloaded ({{status}})",
    "reload_error": "Failed to reload config",
    "shutdown": "Shutdown",
    "shutdown_confirm_title": "Shutdown Server",
    "shutdown_confirm_desc": "The server will stop and the dashboard will become unavailable.",
    "shutdown_confirm": "Confirm Shutdown",
    "shutdown_error": "Failed to shutdown",
    "help": "Runtime is the engine-level dashboard — kernel health, build info, listen addresses, queue / lane status, audit chain status, backups, and lifecycle controls. Use it to answer \"is the daemon healthy and what's it doing right now?\"\n\nHow to use this page:\n\n1. Health row. Active agents, channels, audit entries, uptime, build time, auth mode — all the at-a-glance facts.\n\n2. Audit verify. \"Audit verify\" walks the hash chain and reports valid / invalid. Run after suspicious events or before evidence export.\n\n3. Backup. \"Create backup\" snapshots the daemon's state directory. Backups list shows what you have available.\n\n4. Lifecycle. Reload config (re-reads config.toml, applies hot-reloadable knobs), cleanup sessions (drops idle session state), shut down (stops the daemon — restart externally).\n\nTypical scenarios:\n\n  · Post-config-change: hit Reload, watch new values take effect without restart.\n  · Pre-deploy or pre-incident: take a backup so you can roll back state.\n  · Confirming the audit chain is unbroken before exporting it for review.\n\nThings to know:\n\n  · Reload only picks up hot-reloadable fields — some changes still need a full restart (look for \"needs restart\" hints next to fields).\n  · Cleanup-sessions is non-destructive: it drops in-memory caches, not stored history.\n  · Some per-agent caps (e.g. `max_concurrent_invocations`) are NOT picked up on reload; the agent must respawn.",
    "load_error": "Failed to load runtime overview",
    "load_error_desc": "Core runtime data could not be loaded. Retry after the daemon and API health checks recover.",
    "panics": "Panics",
    "restarts": "Restarts",
    "database": "Database",
    "embedding": "Embedding",
    "proactive_memory": "Proactive Memory",
    "extraction_model": "Extraction Model",
    "config_warnings": "Config Warnings",
    "no_warnings": "No warnings",
    "security": "Security Posture",
    "core_protections": "Core Protections",
    "rate_limiter": "Rate Limiter",
    "websocket_limits": "WebSocket Limits",
    "wasm_sandbox": "WASM Sandbox",
    "auth_mode": "Auth Mode",
    "audit_trail": "Audit Trail",
    "taint_tracking": "Taint Tracking",
    "manifest_signing": "Manifest Signing",
    "features_enabled": "{{count}} features enabled",
    "audit": "Audit Log",
    "audit_verify": "Verify Chain",
    "audit_valid": "Chain Valid",
    "audit_invalid": "Chain Broken",
    "audit_entries": "{{count}} entries",
    "audit_not_verified": "Chain not verified yet",
    "audit_verified_ok": "Audit chain verified ({{count}} entries)",
    "audit_verified_invalid": "Audit chain INVALID - tampering detected",
    "no_audit": "No audit events",
    "backups": "Backups",
    "create_backup": "Create Backup",
    "restore": "Restore",
    "no_backups": "No backups",
    "backup_created": "Backup created",
    "backup_error": "Backup failed",
    "restore_success": "Restore complete. Restart daemon for changes.",
    "restore_error": "Restore failed",
    "restore_confirm_title": "Restore backup",
    "restore_confirm_desc": "Current runtime state will be replaced with data from this backup.",
    "restore_confirm": "Restore backup",
    "delete_backup_confirm_title": "Delete backup",
    "delete_backup_confirm_desc": "This backup file will be permanently removed.",
    "delete_backup_confirm": "Delete this backup?",
    "task_queue": "Task Queue",
    "total_tasks": "Total",
    "pending_count": "Pending",
    "in_progress_count": "In Progress",
    "completed_count": "Completed",
    "failed_count": "Failed",
    "no_tasks": "No queued tasks",
    "retry": "Retry",
    "cancel_task": "Cancel",
    "cleanup_sessions": "Cleanup Sessions",
    "sessions_deleted": "{{count}} sessions deleted",
    "tokens_per_min": "tok/min",
    "max_per_ip": "max/IP",
    "idle_timeout": "Idle Timeout",
    "max_msg_size": "Max Msg Size",
    "max_msg_min": "Max Msg/Min",
    "fuel_limit": "Fuel Limit",
    "timeout": "Timeout"
  },
  "telemetry": {
    "badge": "Observability",
    "title": "Telemetry",
    "subtitle": "System metrics, LLM usage, and HTTP observability.",
    "total_requests": "Total Requests",
    "endpoints": "Endpoints",
    "avg_latency": "Avg Latency",
    "status": "Status",
    "collecting": "Collecting",
    "top_endpoints": "Top Endpoints",
    "latency": "Latency Distribution",
    "prometheus_endpoint": "Prometheus Endpoint",
    "view_raw": "View Raw",
    "help": "Telemetry is the systems-level observability surface — uptime, panics, restarts, request rates, error rates, active sessions, LLM token totals, and the top HTTP endpoints. Numbers come from the same Prometheus endpoint the daemon exposes; this page just renders them.\n\nHow to use this page:\n\n1. Health section. Uptime, panics, restarts — has the daemon been stable.\n\n2. Activity section. Active agents, sessions, total LLM calls, today's cost — what's happening right now.\n\n3. Reliability section. Total requests, error rate, top endpoints — is the API serving traffic cleanly.\n\n4. View raw. \"View raw\" opens the underlying Prometheus text endpoint for ad-hoc scraping or manual debug.\n\nTypical scenarios:\n\n  · Daily morning glance: uptime fine, no panics, error rate normal.\n  · Diagnosing slowness: top-endpoints list points to the offender.\n  · Wiring an external Prometheus / Grafana — point it at the same endpoint linked from \"View raw\".\n\nThings to know:\n\n  · Numbers are live counters; restarts reset most of them. The Prometheus endpoint is the long-term store if you scrape externally.\n  · \"Cost today\" is local-day in the daemon's timezone.\n  · Per-agent breakdown lives on Analytics / Budget; this page is system-wide.",
    "no_data": "No telemetry data yet. Make some API requests to see metrics.",
    "llm_usage": "LLM & Token Usage",
    "total_tokens": "Total Tokens",
    "input_tokens": "Input Tokens",
    "output_tokens": "Output Tokens",
    "llm_calls": "LLM Calls",
    "tool_calls": "Tool Calls",
    "cost_today": "Cost Today",
    "active_sessions": "Sessions",
    "uptime": "Uptime",
    "agents_active": "Active Agents",
    "panics": "Panics",
    "restarts": "Restarts",
    "system_health": "System Health",
    "per_agent": "Per Agent",
    "http_metrics": "HTTP Metrics",
    "tokens_1h": "1h window",
    "section_health": "Health",
    "section_activity": "Activity",
    "section_reliability": "Reliability",
    "error_rate": "Error Rate",
    "input_short": "in",
    "output_short": "out",
    "calls": "calls",
    "tools": "tools",
    "last_updated": "Updated",
    "truncated": "...truncated",
    "unit_tokens": "tok"
  },
  "logs": {
    "title": "Logs",
    "subtitle": "Real-time diagnostic events.",
    "export_json": "Export JSON",
    "timestamp": "Timestamp",
    "module": "Module",
    "agent": "Agent",
    "message": "Message",
    "all_modules": "All Modules",
    "help": "Logs is the live diagnostic stream — structured log events from the daemon's tracing layer, filterable by module and searchable by text. Use it for \"what is the runtime saying right now\" debugging; for tamper-evident history use the Audit trail instead.\n\nHow to use this page:\n\n1. Filter by module. The dropdown narrows to one subsystem (kernel / runtime / channel / …). \"All modules\" shows everything.\n\n2. Search. Free-text match against the message body — useful for grepping for an agent id, a channel name, or an error string.\n\n3. Export JSON. Dump the current view to JSON for sharing with support or feeding into external log tooling.\n\nWhen to use it (vs. Audit trail):\n\n  · Logs — diagnostic, fine-grained, ephemeral. Read for \"what's happening right now\".\n  · Audit trail — privileged actions only, hash-chained, durable. Read for \"who did what and when\".\n\nTypical scenarios:\n\n  · Watching an agent boot and confirming each subsystem registered.\n  · Grepping logs for a request id when chasing a 5xx.\n  · Capturing logs around an incident and exporting JSON for a bug report.\n\nThings to know:\n\n  · Log volume is bounded — old events fall off. Run an external collector (or scrape Prometheus) for long retention.\n  · Module-level filter is server-side; search is client-side over what's loaded.\n  · Logs are not redacted automatically — be careful when exporting if your messages may contain secrets or PII."
  },
  "settings": {
    "title": "Settings",
    "subtitle": "System parameters.",
    "appearance": "Appearance",
    "theme": "Interface Theme",
    "language": "Language",
    "theme_light": "Light",
    "theme_dark": "Dark",
    "system_config": "System Configuration",
    "nav_layout": "Navigation Layout",
    "nav_grouped": "Grouped",
    "nav_collapsible": "Collapsible",
    "theme_desc": "Switch between light and dark mode",
    "language_desc": "Interface display language",
    "nav_layout_desc": "Sidebar navigation style",
    "tools_title": "Tools",
    "tools_search": "Search tools...",
    "change_password": "Change Credentials",
    "change_credentials": "Change Credentials",
    "new_username": "New Username",
    "username_too_short": "Username must be at least 2 characters",
    "pw_current": "Current Password",
    "pw_verify_identity": "Confirm your identity",
    "pw_current_placeholder": "Enter current password to confirm",
    "pw_new": "New Password",
    "pw_leave_blank": "leave blank to keep current",
    "pw_confirm": "Confirm New Password",
    "pw_submit": "Save",
    "pw_success": "Credentials changed. Redirecting to login...",
    "pw_failed": "Failed to change credentials",
    "pw_mismatch": "New passwords do not match",
    "pw_empty": "New password cannot be empty",
    "pw_too_short": "Password must be at least 8 characters",
    "pw_no_changes": "No changes detected",
    "security": "Security",
    "totp_title": "TOTP Second Factor",
    "totp_desc": "Require authenticator app code when approving critical tool executions",
    "totp_enrolled": "Enrolled",
    "totp_not_enrolled": "Not enrolled",
    "totp_enforced": "Enforced",
    "totp_setup": "Set up TOTP",
    "totp_reset": "Reset TOTP",
    "totp_revoke": "Revoke TOTP",
    "totp_scan": "Scan the QR code or enter the secret in your authenticator app:",
    "totp_confirm": "Confirm",
    "totp_recovery_title": "Recovery Codes (save these somewhere safe):",
    "totp_recovery_reveal": "Reveal codes",
    "totp_recovery_hide": "Hide codes",
    "totp_reset_placeholder": "Current TOTP or recovery code",
    "totp_verify_reset": "Verify & Reset",
    "totp_revoke_placeholder": "TOTP or recovery code",
    "totp_confirm_revoke": "Confirm Revoke",
    "totp_setup_failed": "Setup failed",
    "totp_revoke_failed": "Revoke failed",
    "totp_revoked_success": "TOTP revoked. Set second_factor = \"none\" in config.",
    "totp_confirmed_success": "TOTP confirmed. Set second_factor = \"totp\" in config to enforce.",
    "totp_invalid_code": "Invalid code",
    "totp_no_recovery": "No recovery codes remaining. Reset TOTP to generate new ones.",
    "totp_low_recovery": "Only {{count}} recovery code(s) remaining.",
    "auto_dream": "Auto-Dream",
    "auto_dream_on": "Enabled",
    "auto_dream_off": "Disabled",
    "auto_dream_desc": "Periodically asks opt-in agents to consolidate their memory. Toggle individual agents below, then flip the global switch in config.toml ([auto_dream] enabled).",
    "auto_dream_load_err": "Failed to load auto-dream status",
    "auto_dream_no_agents": "No agents have opted in. Set auto_dream_enabled = true on an agent's manifest.",
    "auto_dream_no_agents_registered": "No agents registered yet. Create an agent first, then toggle it on here.",
    "auto_dream_opt_in_hint": "Not enrolled — toggle on to include in the scheduler.",
    "auto_dream_opt_out_running": "Disabled mid-dream — the current run will finish or can be aborted.",
    "auto_dream_cache": "Cache",
    "auto_dream_cache_title": "Prompt cache hit rate for this dream — higher means more of the prefix came from Anthropic's cache instead of being re-billed.",
    "auto_dream_cost_title": "Measured provider cost for this dream turn (input + output, cached tokens billed at the reduced rate).",
    "auto_dream_enrolled": "Enrolled",
    "auto_dream_not_enrolled": "Off",
    "auto_dream_enrolled_ok": "Agent enrolled",
    "auto_dream_unenrolled_ok": "Agent unenrolled",
    "auto_dream_toggle_title": "Opt this agent in or out",
    "auto_dream_every": "every",
    "auto_dream_effective_title": "Resolved threshold — manifest override or global default",
    "auto_dream_sessions_progress_title": "Sessions touched since last dream / required threshold",
    "auto_dream_last": "Last",
    "auto_dream_next": "Next",
    "auto_dream_sessions_since": "sessions since",
    "auto_dream_trigger": "Dream now",
    "auto_dream_fired": "Consolidation fired",
    "auto_dream_abort": "Abort",
    "auto_dream_aborted": "Abort signalled",
    "auto_dream_phase": "Phase",
    "auto_dream_tool_calls": "tool calls",
    "auto_dream_memories_touched": "memories touched",
    "auto_dream_status_running": "Running",
    "auto_dream_status_completed": "Completed",
    "auto_dream_status_failed": "Failed",
    "auto_dream_status_aborted": "Aborted",
    "auto_dream_dur_minute": "m",
    "auto_dream_dur_hour": "h",
    "auto_dream_dur_day": "d",
    "auto_dream_dur_week": "w",
    "help": "Dashboard preferences and account-level controls. This is the place to change your local UI settings, manage TOTP, and trigger Auto-Dream runs — it does not edit kernel configuration on disk (that's the Config page).\n\nWhat lives on this page:\n\n  · UI preferences — language (English / 中文), theme (light / dark), sidebar collapse default. Stored in browser localStorage; per-device.\n  · TOTP enrollment — protect destructive actions (approvals, schedule deletes, plugin install) with a 6-digit one-time code. Setup gives you a QR code and recovery codes; revoke removes the requirement.\n  · Auto-Dream — periodic background pass where the agent reviews its own conversation log and emits memory updates. Trigger one manually, watch a running pass, or enable the daily schedule.\n\nSettings (this page) vs. Config:\n\n  · Settings — per-user, per-browser, lightweight UI / account toggles.\n  · Config (/dashboard/config) — kernel-level TOML editor: providers, channels, MCP servers, plugin policies, runtime caps. Changes there require kernel reload.\n\nThings to know:\n\n  · TOTP secrets are stored encrypted in the kernel vault. If you lose both your authenticator and recovery codes, an admin has to reset by editing config + redeploying.\n  · Auto-Dream runs in the kernel under the agent's own session, so it counts toward that agent's budget. The \"Run now\" button is gated by TOTP if you have it enrolled.\n  · Theme / language changes are instant. The kernel does not need a reload.",
    "backup": "Backup",
    "export_config_btn": "Export Config",
    "export_config_desc": "Download your current configuration as a TOML file.",
    "export_config_title": "Export Configuration"
  },
  "config": {
    "title": "Configuration",
    "desc": "System configuration editor",
    "reload": "Reload",
    "view_raw_toml": "View Raw TOML",
    "raw_toml_title": "config.toml",
    "raw_toml_error": "Failed to load config.toml",
    "hot_reload": "Hot Reload",
    "root_level": "Root Level",
    "no_section": "Section not found",
    "cat_general": "General",
    "cat_memory": "Memory",
    "cat_tools": "Tools",
    "cat_channels": "Channels",
    "cat_security": "Security",
    "cat_network": "Network",
    "cat_infra": "Infrastructure",
    "sec_general": "General",
    "sec_default_model": "Default Model",
    "sec_thinking": "Thinking",
    "sec_budget": "Budget",
    "sec_reload": "Reload",
    "sec_memory": "Memory",
    "sec_proactive_memory": "Proactive Memory",
    "sec_web": "Web",
    "sec_browser": "Browser",
    "sec_links": "Links",
    "sec_media": "Media",
    "sec_tts": "Text to Speech",
    "sec_canvas": "Canvas",
    "sec_channels": "Channels",
    "sec_broadcast": "Broadcast",
    "sec_auto_dream": "Auto-Dream",
    "sec_auto_reply": "Auto Reply",
    "sec_approval": "Approval",
    "sec_exec_policy": "Execution Policy",
    "sec_vault": "Vault",
    "sec_oauth": "OAuth",
    "sec_external_auth": "External Auth",
    "sec_network": "Network",
    "sec_a2a": "A2A",
    "sec_pairing": "Pairing",
    "sec_docker": "Docker",
    "sec_extensions": "Extensions",
    "sec_session": "Session",
    "sec_queue": "Queue",
    "sec_webhook_triggers": "Webhook Triggers",
    "sec_vertex_ai": "Vertex AI",
    "sec_audit": "Audit Log",
    "sec_azure_openai": "Azure OpenAI",
    "sec_compaction": "Compaction",
    "sec_context_engine": "Context Engine",
    "sec_fallback_providers": "Fallback Providers",
    "sec_health_check": "Health Check",
    "sec_heartbeat": "Heartbeat",
    "sec_inbox": "Inbox",
    "sec_llm": "LLM",
    "sec_notification": "Notifications",
    "sec_parallel_tools": "Parallel Tools",
    "sec_plugins": "Plugins",
    "sec_privacy": "Privacy",
    "sec_prompt_intelligence": "Prompt Intelligence",
    "sec_provider_proxy_urls": "Provider Proxy URLs",
    "sec_provider_regions": "Provider Regions",
    "sec_provider_request_timeout_secs": "Provider Request Timeouts (s)",
    "sec_provider_urls": "Provider Base URLs",
    "sec_proxy": "Proxy",
    "sec_rate_limit": "Rate Limit",
    "sec_registry": "Registry",
    "sec_sanitize": "Sanitize",
    "sec_sidecar_channels": "Sidecar Channels",
    "sec_skills": "Skills",
    "sec_taint_rules": "Taint Rules",
    "sec_task_board": "Task Board",
    "sec_telemetry": "Telemetry",
    "sec_tool_invoke": "Tool Invocation",
    "sec_tool_policy": "Tool Policy",
    "sec_tool_results": "Tool Results",
    "sec_tool_timeouts": "Tool Timeouts (s)",
    "sec_triggers": "Triggers",
    "map_empty": "No entries — click Add to create one",
    "map_key": "key",
    "map_value": "value",
    "list_empty": "No items — click Add to create one",
    "add_row": "Add",
    "add_item": "Add",
    "remove_row": "Remove",
    "remove_item": "Remove",
    "expand": "Expand",
    "collapse": "Collapse",
    "fields_unit": "fields",
    "fld_alert_threshold": "Alert Threshold",
    "fld_allowed_commands": "Allowed Commands",
    "fld_allowed_domains": "Allowed Domains",
    "fld_allowed_tags": "Allowed Tags",
    "fld_allowlist": "Allowlist",
    "fld_anchor_path": "Anchor Path",
    "fld_api_key": "API Key",
    "fld_api_key_env": "API Key Env Var",
    "fld_api_listen": "API Listen Address",
    "fld_api_requests_per_minute": "API Requests/Min",
    "fld_api_version": "API Version",
    "fld_artifact_max_age_days": "Artifact Max Age (days)",
    "fld_audience": "Audience",
    "fld_auth_rate_limit_per_ip": "Auth Rate Limit per IP",
    "fld_audio_model": "Audio Model",
    "fld_audio_provider": "Audio Provider",
    "fld_audio_transcription": "Audio Transcription",
    "fld_auto_approve": "Auto Approve",
    "fld_auto_approve_autonomous": "Auto Approve Autonomous",
    "fld_auto_memorize": "Auto Memorize",
    "fld_auto_reconnect": "Auto Reconnect",
    "fld_auto_retrieve": "Auto Retrieve",
    "fld_auto_start_observability_stack": "Auto Start Observability Stack",
    "fld_base_url": "Base URL",
    "fld_bootstrap_peers": "Bootstrap Peers",
    "fld_budget_tokens": "Budget Tokens",
    "fld_cache_ttl_minutes": "Cache TTL (minutes)",
    "fld_cache_ttl_secs": "Cache TTL (s)",
    "fld_check_interval_secs": "Check Interval (s)",
    "fld_chromium_path": "Chromium Path",
    "fld_cleanup_interval_hours": "Cleanup Interval (hours)",
    "fld_claim_ttl_secs": "Claim TTL (s)",
    "fld_client_id": "Client ID",
    "fld_client_secret_env": "Client Secret Env Var",
    "fld_confidence_decay_rate": "Confidence Decay Rate",
    "fld_consolidation_interval_hours": "Consolidation Interval (hours)",
    "cleanup_interval_hours_0": "Disabled",
    "cleanup_interval_hours_1": "Every hour",
    "cleanup_interval_hours_6": "Every 6 hours",
    "cleanup_interval_hours_12": "Every 12 hours",
    "cleanup_interval_hours_24": "Daily",
    "cleanup_interval_hours_48": "Every 2 days",
    "cleanup_interval_hours_168": "Weekly",
    "consolidation_interval_hours_0": "Disabled",
    "consolidation_interval_hours_1": "Every hour",
    "consolidation_interval_hours_6": "Every 6 hours",
    "consolidation_interval_hours_12": "Every 12 hours",
    "consolidation_interval_hours_24": "Daily",
    "consolidation_interval_hours_48": "Every 2 days",
    "consolidation_interval_hours_168": "Weekly",
    "fld_consolidation_threshold": "Consolidation Threshold",
    "fld_container_prefix": "Container Prefix",
    "fld_cooldown_secs": "Cooldown (s)",
    "fld_cpu_limit": "CPU Limit",
    "fld_custom_block_patterns": "Custom Block Patterns",
    "fld_credentials_path": "Credentials Path",
    "fld_debounce_ms": "Debounce (ms)",
    "fld_decay_rate": "Decay Rate",
    "fld_default_agent": "Default Agent",
    "fld_default_max_llm_tokens_per_hour": "Max LLM Tokens/Hour",
    "fld_default_timeout_secs": "Default Timeout (s)",
    "fld_deployment": "Deployment",
    "fld_directory": "Directory",
    "fld_disable_input_sanitizer": "Disable Input Sanitizer",
    "fld_disabled": "Disabled Skills",
    "fld_discord": "Discord",
    "fld_duplicate_threshold": "Duplicate Threshold",
    "fld_email": "Email",
    "fld_emit_caller_trace_headers": "Emit Caller Trace Headers",
    "fld_embedding_api_key_env": "Embedding API Key Env Var",
    "fld_embedding_model": "Embedding Model",
    "fld_embedding_provider": "Embedding Provider",
    "fld_enabled": "Enabled",
    "fld_endpoint": "Endpoint",
    "fld_engine": "Engine",
    "fld_env_passthrough_denied_patterns": "Env Passthrough Denied Patterns",
    "fld_extra_dirs": "Extra Skill Directories",
    "fld_extract_categories": "Extract Categories",
    "fld_extraction_model": "Extraction Model",
    "fld_extraction_threshold": "Extraction Threshold",
    "fld_fold_min_batch_size": "Fold Min Batch Size",
    "fld_github_client_id": "GitHub Client ID",
    "fld_google_chat": "Google Chat",
    "fld_google_client_id": "Google Client ID",
    "fld_hash_prompts": "Hash Prompts",
    "fld_headless": "Headless Mode",
    "fld_health_check_interval_secs": "Health Check Interval (s)",
    "fld_history_fold_after_turns": "History Fold After (turns)",
    "fld_http_proxy": "HTTP Proxy",
    "fld_https_proxy": "HTTPS Proxy",
    "fld_idle_timeout_secs": "Idle Timeout (s)",
    "fld_image": "Image",
    "fld_image_description": "Image Description",
    "fld_image_provider": "Image Provider",
    "fld_issuer_url": "Issuer URL",
    "fld_keep_recent": "Keep Recent",
    "fld_language": "Language",
    "fld_listen_addresses": "Listen Addresses",
    "fld_listen_path": "Listen Path",
    "fld_load_user": "Load User Skills",
    "fld_lock_dir": "Lock Directory",
    "fld_log_level": "Log Level",
    "fld_matrix": "Matrix",
    "fld_mattermost": "Mattermost",
    "fld_max_age_secs": "Max Age (s)",
    "fld_max_artifact_bytes": "Max Artifact Bytes",
    "fld_max_bytes_per_turn": "Max Bytes per Turn",
    "fld_max_chunk_chars": "Max Chunk Chars",
    "fld_max_concurrency": "Max Concurrency",
    "fld_max_concurrent": "Max Concurrent",
    "fld_max_content_bytes": "Max Content Bytes",
    "fld_max_cron_jobs": "Max Cron Jobs",
    "fld_max_daily_usd": "Max Daily USD",
    "fld_max_depth": "Max Depth",
    "fld_max_depth_global": "Max Global Depth",
    "fld_max_depth_per_agent": "Max Depth per Agent",
    "fld_max_devices": "Max Devices",
    "fld_max_hourly_usd": "Max Hourly USD",
    "fld_max_html_bytes": "Max HTML Bytes",
    "fld_max_links": "Max Links",
    "fld_max_memories_per_agent": "Max Memories per Agent",
    "fld_max_message_length": "Max Message Length",
    "fld_max_monthly_usd": "Max Monthly USD",
    "fld_max_output_bytes": "Max Output Bytes",
    "fld_max_payload_bytes": "Max Payload Bytes",
    "fld_max_peers": "Max Peers",
    "fld_max_per_event": "Max Triggers per Event",
    "fld_max_retries": "Max Retries",
    "fld_max_retrieve": "Max Retrieve",
    "fld_max_sessions": "Max Sessions",
    "fld_max_sessions_per_agent": "Max Sessions per Agent",
    "fld_max_summary_tokens": "Max Summary Tokens",
    "fld_max_text_length": "Max Text Length",
    "fld_max_versions_per_agent": "Max Versions per Agent",
    "fld_max_workflow_secs": "Max Workflow (s)",
    "fld_max_ws_per_ip": "Max WebSocket Connections per IP",
    "fld_mcp_default_safety": "MCP Default Safety",
    "fld_mcp_readonly_allowlist": "MCP Read-Only Allowlist",
    "fld_mdns_enabled": "mDNS Enabled",
    "fld_memory_limit": "Memory Limit",
    "fld_microsoft_client_id": "Microsoft Client ID",
    "fld_min_hours": "Minimum Hours",
    "fld_min_sessions": "Minimum Sessions",
    "fld_mode": "Mode",
    "fld_model": "Model",
    "fld_network": "Network",
    "fld_network_enabled": "Network Enabled",
    "fld_no_output_timeout_secs": "No Output Timeout (s)",
    "fld_no_proxy": "No Proxy",
    "fld_ntfy_topic": "Ntfy Topic",
    "fld_ntfy_url": "Ntfy URL",
    "fld_otlp_endpoint": "OTLP Endpoint",
    "fld_path": "Path",
    "fld_pids_limit": "PIDs Limit",
    "fld_plugin": "Plugin",
    "fld_plugin_stack": "Plugin Stack",
    "fld_plugin_stack_weights": "Plugin Stack Weights",
    "fld_poll_interval_secs": "Poll Interval (s)",
    "fld_project_id": "Project ID",
    "fld_prometheus_enabled": "Prometheus Enabled",
    "fld_prompt_caching": "Prompt Caching",
    "fld_provider": "Provider",
    "fld_push_provider": "Push Provider",
    "fld_rate_limit_per_minute": "Rate Limit/Min",
    "fld_read_only_root": "Read-Only Root",
    "fld_redact_patterns": "Redact Patterns",
    "fld_reconnect_max_attempts": "Max Reconnect Attempts",
    "fld_reconnect_max_backoff_secs": "Max Reconnect Backoff (s)",
    "fld_redirect_url": "Redirect URL",
    "fld_region": "Region",
    "fld_registry_mirror": "Registry Mirror URL",
    "fld_require_approval": "Require Approval",
    "fld_retention_days": "Retention Days",
    "fld_retry_after_secs": "Retry After (s)",
    "fld_reuse_cool_secs": "Reuse Cooldown (s)",
    "fld_routes": "Routes",
    "fld_safe_bins": "Safe Binaries",
    "fld_sample_rate": "Sample Rate",
    "fld_scopes": "Scopes",
    "fld_search_provider": "Search Provider",
    "fld_service_name": "Service Name",
    "fld_session_ttl_hours": "Session TTL (hours)",
    "fld_session_ttl_secs": "Session TTL (s)",
    "fld_shared_secret": "Shared Secret",
    "fld_signal": "Signal",
    "fld_slack": "Slack",
    "fld_slack_client_id": "Slack Client ID",
    "fld_sqlite_path": "SQLite Path",
    "fld_spill_threshold_bytes": "Spill Threshold Bytes",
    "fld_stable_prefix_mode": "Stable Prefix Mode",
    "fld_strategy": "Strategy",
    "fld_stream_thinking": "Stream Thinking",
    "fld_subagent_max_concurrent": "Max Concurrent Subagents",
    "fld_subagent_max_depth": "Max Subagent Depth",
    "fld_suppress_patterns": "Suppress Patterns",
    "fld_sweep_interval_secs": "Sweep Interval (s)",
    "fld_task_ttl_secs": "Task TTL (s)",
    "fld_teams": "Teams",
    "fld_telegram": "Telegram",
    "fld_threshold_messages": "Threshold Messages",
    "fld_timeout_secs": "Timeout (s)",
    "fld_token_env": "Token Env Var",
    "fld_token_expiry_secs": "Token Expiry (s)",
    "fld_token_threshold_ratio": "Token Threshold Ratio",
    "fld_totp_issuer": "TOTP Issuer Name",
    "fld_usage_footer": "Usage Footer",
    "usage_footer_off": "Off",
    "usage_footer_tokens": "Tokens",
    "usage_footer_cost": "Cost",
    "usage_footer_full": "Full (tokens + cost)",
    "fld_video_description": "Video Description",
    "fld_viewport_height": "Viewport Height",
    "fld_viewport_width": "Viewport Width",
    "fld_whatsapp": "WhatsApp",
    "fld_workdir": "Work Directory",
    "fld_workspaces_dir": "Workspaces Directory",
    "fld_ws_debounce_chars": "WS Debounce Chars",
    "fld_ws_debounce_ms": "WS Debounce (ms)",
    "fld_ws_idle_timeout_secs": "WS Idle Timeout (s)",
    "fld_ws_messages_per_minute": "WS Messages/Min",
    "fld_ws_terminal_messages_per_minute": "WS Terminal Messages/Min",
    "desc_api_listen": "Address and port the API server listens on, e.g. 127.0.0.1:4545 (local-only) or 0.0.0.0:4545 (all interfaces)",
    "desc_api_key": "API key for authenticating dashboard and API requests",
    "desc_api_key_env": "Environment variable name that holds the provider API key",
    "desc_log_level": "Logging verbosity level",
    "desc_network_enabled": "Enable P2P networking for multi-node communication",
    "desc_mode": "Kernel operating mode — stable, default, or dev",
    "desc_language": "Default language for agent responses",
    "desc_usage_footer": "What usage info to show after each response",
    "desc_stable_prefix_mode": "Use stable message ID prefixes for deterministic caching",
    "desc_prompt_caching": "Enable prompt caching to reduce API costs on repeated prefixes",
    "desc_max_cron_jobs": "Maximum number of scheduled cron jobs per agent",
    "desc_workspaces_dir": "Directory for storing agent workspace data",
    "desc_provider": "LLM provider to use for this model",
    "desc_model": "Model identifier to use for inference",
    "desc_base_url": "Custom API base URL (leave empty for provider default)",
    "desc_sqlite_path": "Path to the SQLite database file for memory storage",
    "desc_embedding_model": "Model used for generating text embeddings",
    "desc_consolidation_threshold": "Number of memories before triggering consolidation",
    "desc_decay_rate": "Rate at which memory relevance decays over time (0-1)",
    "desc_embedding_provider": "Embedding provider (auto = probe all providers)",
    "desc_embedding_api_key_env": "Environment variable for the embedding provider API key",
    "desc_consolidation_interval_hours": "Hours between automatic memory consolidation runs (0 = disabled)",
    "desc_enabled": "Enable or disable this feature",
    "desc_auto_memorize": "Automatically extract and store facts from conversations",
    "desc_auto_retrieve": "Automatically recall relevant memories during conversations",
    "desc_max_retrieve": "Maximum number of memories to retrieve per query",
    "desc_extraction_threshold": "Confidence threshold for automatic memory extraction (0-1)",
    "desc_extraction_model": "Model used for memory extraction (leave empty for default)",
    "desc_extract_categories": "Categories of information to extract (e.g. facts, preferences)",
    "desc_session_ttl_hours": "Hours before an inactive session expires",
    "desc_confidence_decay_rate": "Rate at which memory confidence decreases over time",
    "desc_duplicate_threshold": "Similarity threshold for deduplicating memories (0-1)",
    "desc_max_memories_per_agent": "Maximum memories stored per agent",
    "desc_search_provider": "Web search provider for agent research tasks",
    "desc_cache_ttl_minutes": "Minutes to cache web search results",
    "desc_headless": "Run browser in headless mode (no visible window)",
    "desc_viewport_width": "Browser viewport width in pixels",
    "desc_viewport_height": "Browser viewport height in pixels",
    "desc_timeout_secs": "Timeout in seconds before the operation is cancelled",
    "desc_idle_timeout_secs": "Seconds of inactivity before resource is released",
    "desc_max_sessions": "Maximum number of concurrent browser sessions",
    "desc_chromium_path": "Path to a custom Chromium binary (leave empty for bundled)",
    "desc_listen_addresses": "P2P network listen addresses in multiaddr format (e.g. /ip4/0.0.0.0/tcp/4001)",
    "desc_bootstrap_peers": "Initial peer addresses to connect to on startup",
    "desc_mdns_enabled": "Enable mDNS for automatic local peer discovery",
    "desc_max_peers": "Maximum number of P2P peer connections",
    "desc_shared_secret": "Shared secret for P2P network authentication",
    "desc_auto_reconnect": "Automatically reconnect to MCP servers on disconnect",
    "desc_reconnect_max_attempts": "Maximum number of reconnection attempts",
    "desc_reconnect_max_backoff_secs": "Maximum backoff time between reconnection attempts",
    "desc_health_check_interval_secs": "Seconds between health check pings to MCP servers",
    "desc_image_description": "Enable automatic image description using vision models",
    "desc_audio_transcription": "Enable automatic audio transcription",
    "desc_video_description": "Enable automatic video description",
    "desc_max_concurrency": "Maximum number of concurrent media processing tasks",
    "desc_image_provider": "Provider for image generation/analysis",
    "desc_audio_model": "Model used for audio transcription (leave empty for provider default)",
    "desc_audio_provider": "Provider for audio transcription",
    "desc_max_links": "Maximum number of links to extract per message",
    "desc_max_content_bytes": "Maximum content size to fetch from links",
    "desc_budget_tokens": "Maximum tokens allocated for extended thinking",
    "desc_stream_thinking": "Stream thinking tokens to the client in real time",
    "desc_max_hourly_usd": "Maximum spend per hour in USD (0 = unlimited)",
    "desc_max_daily_usd": "Maximum spend per day in USD (0 = unlimited)",
    "desc_max_monthly_usd": "Maximum spend per month in USD (0 = unlimited)",
    "desc_alert_threshold": "Percentage of budget used before alerting (0-1)",
    "desc_default_max_llm_tokens_per_hour": "Default token rate limit per agent per hour",
    "desc_require_approval": "Tool categories that require human approval before execution",
    "desc_auto_approve_autonomous": "Auto-approve tool calls in autonomous mode",
    "desc_auto_approve": "Auto-approve all tool calls (overrides require_approval)",
    "desc_safe_bins": "Binaries allowed in allowlist execution mode",
    "desc_allowed_commands": "Shell commands allowed in allowlist execution mode",
    "desc_max_output_bytes": "Maximum output size from command execution",
    "desc_no_output_timeout_secs": "Seconds with no output before killing a running command",
    "desc_strategy": "Message delivery strategy for multi-channel broadcast",
    "desc_routes": "Channel routing rules for broadcast messages",
    "desc_max_concurrent": "Maximum concurrent auto-reply processing tasks",
    "desc_suppress_patterns": "Regex patterns for messages to suppress auto-reply",
    "desc_max_html_bytes": "Maximum HTML canvas size in bytes",
    "desc_allowed_tags": "HTML tags allowed in canvas content",
    "desc_max_text_length": "Maximum text length for TTS conversion",
    "desc_image": "Docker image to use for sandboxed execution",
    "desc_container_prefix": "Prefix for Docker container names",
    "desc_workdir": "Working directory inside the Docker container",
    "desc_network": "Docker network to attach containers to",
    "desc_memory_limit": "Docker container memory limit (e.g. 512m, 1g)",
    "desc_cpu_limit": "Docker container CPU limit (e.g. 1.0 = 1 core)",
    "desc_read_only_root": "Mount container root filesystem as read-only",
    "desc_pids_limit": "Maximum number of processes in the container",
    "desc_reuse_cool_secs": "Seconds before a stopped container can be reused",
    "desc_max_age_secs": "Maximum container lifetime in seconds",
    "desc_max_devices": "Maximum paired devices for remote approval",
    "desc_token_expiry_secs": "Seconds before a pairing token expires",
    "desc_push_provider": "Push notification provider for mobile approvals",
    "desc_ntfy_url": "Ntfy server URL for push notifications",
    "desc_ntfy_topic": "Ntfy topic name for push notifications",
    "desc_totp_issuer": "Issuer name displayed in the TOTP authenticator app",
    "desc_token_env": "Environment variable holding the webhook authentication token",
    "desc_max_payload_bytes": "Maximum webhook payload size in bytes",
    "desc_rate_limit_per_minute": "Maximum webhook requests per minute",
    "desc_project_id": "Google Cloud project ID for Vertex AI",
    "desc_region": "Google Cloud region for Vertex AI (e.g. us-central1)",
    "desc_credentials_path": "Path to Google Cloud service account credentials JSON",
    "desc_google_client_id": "Google OAuth client ID",
    "desc_github_client_id": "GitHub OAuth client ID",
    "desc_microsoft_client_id": "Microsoft OAuth client ID",
    "desc_slack_client_id": "Slack OAuth client ID",
    "desc_retention_days": "Days to keep session history before cleanup",
    "desc_max_sessions_per_agent": "Maximum saved sessions per agent",
    "desc_cleanup_interval_hours": "Hours between session cleanup runs",
    "desc_max_depth_per_agent": "Maximum queued tasks per agent",
    "desc_max_depth_global": "Maximum queued tasks across all agents",
    "desc_task_ttl_secs": "Seconds before a queued task expires",
    "desc_issuer_url": "OIDC issuer URL for external authentication",
    "desc_client_id": "OAuth client ID for external auth provider",
    "desc_client_secret_env": "Environment variable for OAuth client secret",
    "desc_redirect_url": "OAuth callback URL",
    "desc_scopes": "OAuth scopes to request",
    "desc_allowed_domains": "Email domains allowed for external auth login",
    "desc_audience": "Expected audience claim in the JWT token",
    "desc_session_ttl_secs": "External auth session lifetime in seconds",
    "desc_listen_path": "URL path for the A2A protocol endpoint",
    "desc_debounce_ms": "Milliseconds to debounce config file change detection",
    "desc_allowlist": "Tool name glob patterns that may be invoked via the REST endpoint (requires enabled = true)",
    "desc_anchor_path": "Path to an external Merkle-tip anchor file for tamper detection; leave empty to use the default data_dir/audit.anchor",
    "desc_api_requests_per_minute": "API token budget per minute per IP using the GCRA algorithm",
    "desc_api_version": "Azure OpenAI API version (e.g. 2024-02-01)",
    "desc_artifact_max_age_days": "Days before spill artifacts are evicted at daemon startup; set to 0 to disable eviction",
    "desc_auth_rate_limit_per_ip": "Maximum login attempts per IP per 15-minute window; set to 0 to disable",
    "desc_auto_start_observability_stack": "Auto-start the bundled Grafana/Prometheus/Tempo/OTel Docker stack on daemon boot",
    "desc_cache_ttl_secs": "Seconds before the registry cache is considered stale and re-downloaded",
    "desc_claim_ttl_secs": "Seconds an in-progress task may stay claimed before the sweeper resets it to pending; 0 disables",
    "desc_cooldown_secs": "Default cooldown between trigger firings in seconds",
    "desc_custom_block_patterns": "Additional regex patterns that trigger a block or warning during input sanitization",
    "desc_default_agent": "Agent name to route inbox files to when no agent: directive is present",
    "desc_default_timeout_secs": "Default threshold in seconds before an agent is considered unresponsive",
    "desc_deployment": "Azure OpenAI deployment name (e.g. gpt-4o); falls back to AZURE_OPENAI_DEPLOYMENT or the default model name",
    "desc_directory": "Directory to watch for incoming files",
    "desc_disable_input_sanitizer": "Emergency opt-out — disables all input sanitization; prefer mode = warn for monitoring without blocking",
    "desc_disabled": "Skill names to skip at load time without deleting their directories",
    "desc_emit_caller_trace_headers": "Emit x-librefang-agent/session/step-id headers on outbound LLM requests for observability correlation",
    "desc_endpoint": "Azure resource endpoint URL (e.g. https://my-resource.openai.azure.com)",
    "desc_engine": "Built-in context engine: default, summary (LLM-based compaction), or no_compact",
    "desc_env_passthrough_denied_patterns": "Glob patterns blocking skill env-var passthrough requests; overridable per-skill via env_passthrough_per_skill",
    "desc_extra_dirs": "Additional skill directories to scan in addition to ~/.librefang/skills/",
    "desc_fold_min_batch_size": "Minimum stale tool-result messages required before a fold pass runs; reduces aux-LLM round-trips per turn",
    "desc_hash_prompts": "Hash prompts using SHA-256 for version identification",
    "desc_history_fold_after_turns": "Summarise stale tool results via aux-LLM after this many turns to keep context compact",
    "desc_http_proxy": "HTTP proxy URL (e.g. http://proxy:8080); falls back to HTTP_PROXY env var",
    "desc_https_proxy": "HTTPS proxy URL (e.g. http://proxy:8080); falls back to HTTPS_PROXY env var",
    "desc_keep_recent": "Number of recent turns to preserve verbatim during compaction or heartbeat context pruning",
    "desc_load_user": "Load user-installed skills from the skills directory",
    "desc_max_artifact_bytes": "Maximum bytes for a single artifact write; oversized results fall back to truncation",
    "desc_max_bytes_per_turn": "Cumulative byte cap across all tool results in one LLM turn before spill or truncation is applied",
    "desc_max_chunk_chars": "Maximum characters per LLM summarization chunk during compaction",
    "desc_max_depth": "Maximum trigger recursion depth",
    "desc_max_message_length": "Maximum allowed input message length in bytes",
    "desc_max_per_event": "Maximum number of triggers that can fire from a single event",
    "desc_max_retries": "Maximum LLM summarization retries during compaction, or auto-resets before marking a stuck task failed",
    "desc_max_summary_tokens": "Maximum tokens for the LLM-generated compaction summary",
    "desc_max_versions_per_agent": "Maximum prompt versions to retain per agent",
    "desc_max_workflow_secs": "Maximum workflow execution time in seconds",
    "desc_max_ws_per_ip": "Maximum concurrent WebSocket connections per IP address",
    "desc_mcp_default_safety": "Default safety class for MCP tools without readOnlyHint annotations: read_only or write_shared",
    "desc_mcp_readonly_allowlist": "MCP tool names treated as ReadOnly regardless of mcp_default_safety (use fully-namespaced form)",
    "desc_no_proxy": "Comma-separated hosts or domains that bypass the proxy; falls back to NO_PROXY env var",
    "desc_otlp_endpoint": "OTLP gRPC endpoint for OpenTelemetry trace export",
    "desc_path": "File system path for vault storage",
    "desc_plugin": "Context engine plugin name resolved from ~/.librefang/plugins/<name>/plugin.toml",
    "desc_plugin_stack": "Ordered list of plugin names to stack as a multi-layer context engine",
    "desc_plugin_stack_weights": "Priority weight for each layer in the plugin stack; higher weight means recalled memories appear first",
    "desc_poll_interval_secs": "Seconds between inbox directory scans",
    "desc_prometheus_enabled": "Expose a Prometheus metrics endpoint at /api/metrics",
    "desc_redact_patterns": "Additional regex patterns to match and redact or pseudonymize alongside built-in PII patterns",
    "desc_registry_mirror": "Mirror/proxy prefix for GitHub URLs (e.g. https://ghproxy.cn) to improve access in restricted networks",
    "desc_retry_after_secs": "Value sent in the Retry-After header when a request is rate limited",
    "desc_sample_rate": "Trace sampling rate from 0.0 (no traces) to 1.0 (sample everything)",
    "desc_service_name": "Service name reported to the OTel collector",
    "desc_spill_threshold_bytes": "Tool results larger than this are spilled to the artifact store; the agent receives a stub handle",
    "desc_subagent_max_concurrent": "Maximum number of subagents running concurrently",
    "desc_subagent_max_depth": "Maximum nesting depth for subagent invocations",
    "desc_sweep_interval_secs": "Seconds between task-board sweeper scans for stuck in-progress tasks",
    "desc_threshold_messages": "Number of messages that triggers context compaction",
    "desc_token_threshold_ratio": "Fraction of the model context window at which token-based compaction fires (0.0–1.0)",
    "desc_ws_debounce_chars": "Flush the text buffer when it exceeds this many characters",
    "desc_ws_debounce_ms": "Text-delta debounce interval in milliseconds before flushing to the client",
    "desc_ws_idle_timeout_secs": "Seconds of WebSocket inactivity before the connection is closed",
    "desc_ws_messages_per_minute": "Maximum WebSocket messages per minute per connection",
    "desc_ws_terminal_messages_per_minute": "Maximum terminal WebSocket input messages per minute per connection",
    "saved_restart": "Saved (restart required)",
    "saved_reload_failed": "Saved but reload failed",
    "load_error": "Failed to load configuration",
    "reload_success": "Config reloaded",
    "search_placeholder": "Search fields...",
    "unsaved": "unsaved",
    "discard": "Discard",
    "save_all": "Save All",
    "no_results": "No fields match your search",
    "reset_default": "Reset to default",
    "unsaved_warning": "You have unsaved changes. Discard them?",
    "save_failed": "Save failed",
    "changes": "Unsaved changes",
    "reset_all": "Reset all",
    "reset_section": "Reset section",
    "searching_all": "Searching all sections..."
  },
  "chat": {
    "title": "Chat",
    "neural_terminal": "Neural Terminal",
    "group_standalone": "Standalone",
    "hand_coordinator": "coordinator",
    "web_search_tooltip": "Web Search: {{mode}}. Requires a search API key (Tavily, Brave, Jina, or Perplexity) in config.toml [web] section.",
    "web_search_key_hint": "Needs search API key in config",
    "web_search_no_key": "No search API key configured. Click to open settings.",
    "web_search_setup": "Search",
    "web_search_configure": "Configure API key",
    "select_agent": "Select Agent",
    "select_agent_desc": "Choose an agent from the list to establish a communication link.",
    "transmit_command": "Transmit neural pulse...",
    "send": "Send",
    "secure_link": "Secure Link",
    "standby": "Standby",
    "end_history": "End of history",
    "welcome_system": "Neural bridge established.",
    "load_earlier_messages": "Load {{count}} earlier messages",
    "input_placeholder_with_agent": "Transmit command to {{name}}...",
    "generating": "Generating...",
    "clear_chat": "Clear Chat",
    "session": "Session",
    "session_unpinned": "Unpinned",
    "sessions_title": "Sessions",
    "send_hint": "Enter to send, Cmd+Enter for newline",
    "stop_hint": "Stop generating",
    "voice_input": "Voice input",
    "voice_stop": "Stop recording",
    "voice_recording": "Listening...",
    "voice_transcribing": "Transcribing...",
    "voice_not_configured": "Voice input requires an STT provider. Configure one in Config → Tools → Media.",
    "deep_thinking": "Deep Thinking",
    "deep_thinking_hint": "Ask the model to reason step-by-step (reasoning models only)",
    "show_thinking": "Show Thinking",
    "show_thinking_hint": "Display the model's reasoning process in replies",
    "thinking_label": "Thinking",
    "you": "You",
    "bot": "Bot",
    "ws_connected": "WS",
    "ws_streaming": "Streaming",
    "auth_missing": "API key for provider \"{{provider}}\" is not configured. Please set it in Settings > Providers before chatting.",
    "provider_offline": "Local provider \"{{provider}}\" is not running. Please start the service first.",
    "approval_required": "Approval Required",
    "approval_tool": "Tool",
    "approval_agent": "Agent {{agent}} requests to execute",
    "approval_risk_high": "High Risk",
    "approval_risk_medium": "Medium Risk",
    "approval_risk_low": "Low Risk",
    "switch_model": "Switch Model",
    "search_models": "Search models...",
    "loading_models": "Loading…",
    "no_models_found": "No models found.",
    "unable_to_load_models": "Unable to load models",
    "model_update_failed": "Failed to update model. Please try again.",
    "retry": "Retry",
    "no_model": "No model",
    "copy": "Copy",
    "copied": "Copied",
    "speak": "Speak",
    "pause": "Pause",
    "resume": "Resume",
    "tts_unavailable": "No TTS provider configured",
    "tts_generating": "Generating speech...",
    "tts_error": "Speech generation failed",
    "tts_empty": "No readable text",
    "cmd_help": "Show available commands",
    "cmd_clear": "Clear chat history",
    "cmd_agents": "List available agents",
    "cmd_info": "Show current agent info",
    "cmd_new": "Start a new session (new session id)",
    "cmd_compact": "Compress context to save space",
    "cmd_reset": "Reset session (clear history)",
    "cmd_reboot": "Reboot session (clear context)",
    "cmd_stop": "Cancel current run",
    "cmd_model": "Show or switch model",
    "cmd_usage": "Show session token usage",
    "cmd_context": "Show context pressure",
    "cmd_verbose": "Toggle verbose level",
    "cmd_budget": "Show budget status",
    "cmd_peers": "Show connected peers",
    "cmd_a2a": "Show A2A agents",
    "cmd_queue": "Show agent queue status",
    "cmd_col_command": "Command",
    "cmd_col_desc": "Description",
    "no_agents_available": "No agents available.",
    "no_agent_selected": "No agent selected.",
    "info_model": "Model",
    "info_provider": "Provider",
    "info_state": "State",
    "ws_not_connected": "WebSocket not connected. Please refresh the page.",
    "command_timeout": "Command timed out or connection dropped — please try again.",
    "delete_session": "Delete session",
    "export": "Export",
    "export_markdown": "Export as Markdown",
    "new_session": "New session",
    "search_providers": "Search providers...",
    "select_provider": "Select Provider",
    "tool_calls": "{{count}} tool calls",
    "tool_error": "Error",
    "tool_input": "Input",
    "tool_result": "Result",
    "tool_running": "Running…"
  },
  "goals": {
    "title": "Goals",
    "subtitle": "Strategic planning and task tracking.",
    "total": "Total",
    "pending": "Pending",
    "in_progress": "In Progress",
    "completed": "Completed",
    "create_goal": "Create Goal",
    "goal_title_placeholder": "Goal Title",
    "goal_desc_placeholder": "Description",
    "goal_tree": "Goal Tree",
    "title_label": "Title",
    "desc_label": "Description",
    "add_examples": "Add Examples",
    "add_example_goals": "Add Example Goals",
    "toggle_reset": "Complete / Reset",
    "delete_confirm": "Are you sure you want to delete this goal?",
    "pick_template": "Choose a Template",
    "pick_template_desc": "Pick a template to get started quickly with pre-defined goals.",
    "use_template": "Use Template",
    "apply_template_partial": "Created {{succeeded}}/{{total}} goals, failed {{failed}}.",
    "overall_progress": "Overall Progress",
    "clear_all": "Clear All",
    "clear_all_confirm": "Delete all goals?",
    "clear_all_partial": "Deleted {{succeeded}}/{{total}} goals, failed {{failed}}.",
    "help": "Goals is the strategic-planning surface — a tree of objectives the agent (or you) is working towards, with progress, status, and parent / child relationships. Templates seed common goal shapes; the tree view shows hierarchy and roll-up progress.\n\nHow to use this page:\n\n1. Create. \"Create goal\" opens a form for title, description, parent goal, and status. Or \"Pick template\" to apply a pre-built goal tree (e.g. \"ship a feature\", \"research a topic\").\n\n2. Track. Each node shows pending / in-progress / completed. Parent progress aggregates from children. Edit a node inline to flip its state or refine its description.\n\n3. Prune. \"Clear all\" wipes the tree (with a confirm) — useful when starting a new initiative.\n\nWhen to use it (vs. Scheduler / Workflows):\n\n  · Goals — what we want. Long-lived intentions, often agent-readable.\n  · Scheduler / Workflows — how it gets done. Concrete fires and steps.\n\nTypical scenarios:\n\n  · Giving an agent a long-term direction it can refer back to during planning.\n  · Tracking a multi-week project as a tree the human and the agent both see.\n\nThings to know:\n\n  · Templates are starting points — feel free to edit the tree after applying.\n  · Deleting a parent deletes its children. Confirm before \"Clear all\"."
  },
  "sessions": {
    "title": "Sessions",
    "subtitle": "Active agent conversations and historical execution contexts.",
    "active_count": "active",
    "total": "total",
    "search_placeholder": "Search by agent name...",
    "empty_title": "No sessions",
    "empty_desc": "Sessions will appear when agents start conversations.",
    "unknown_agent": "Unknown Agent",
    "just_now": "just now",
    "help": "Sessions are the live and historical conversation contexts of every agent. Each session is a thread of messages + tool calls bound to one agent and one origin (channel, cron, A2A peer, or manual). This page lets you browse them, label them, and clean up.\n\nHow to use this page:\n\n1. Search & filter. Type to search by agent, label, or recent message text. Active vs. idle is auto-derived from last activity.\n\n2. Label. \"Set label\" tags a session so it's easier to find later — useful for long-running threads.\n\n3. Delete. Remove old sessions you don't need. The agent's full message history for that thread goes with it.\n\nTypical scenarios:\n\n  · Finding the session where the agent and a user worked through a specific problem.\n  · Pruning channel sessions that have piled up after a busy week.\n  · Confirming an agent has the session you expect for a given (channel, chat) pair before debugging.\n\nThings to know:\n\n  · Channel messages always use a canonical session id — `(agent, \"<channel>:<chat>\")` — so a user always lands in the same thread.\n  · Cron fires share a single per-agent session; that's by design (prompt cache reuse) but it does mean cron history can grow.\n  · Deleting a session is irreversible. Memory entries the session created stay (Memory page is separate).",
    "set_label": "Set label",
    "no_label": "add label",
    "label_placeholder": "Label...",
    "open_in_chat": "Open this session in the chat page"
  },
  "approvals": {
    "title": "Approvals",
    "subtitle": "Review and authorize critical agent actions.",
    "pending_review": "Pending Review",
    "skill_candidates_pending": "{{count}} skill candidates pending review",
    "approve": "Approve",
    "reject": "Reject",
    "approvedToast": "Approved",
    "rejectedToast": "Rejected",
    "totpRequired": "TOTP code required. Use the Approvals page.",
    "status": {
      "pending": "Pending",
      "approved": "Approved",
      "rejected": "Rejected",
      "expired": "Expired"
    },
    "queue_clear": "Queue Clear",
    "queue_clear_desc": "No pending actions.",
    "help": "Approvals is the human-in-the-loop queue. When an agent invokes a tool that's flagged as \"requires approval\" (destructive shell commands, large-spend LLM calls, sensitive HTTP, etc.) the call pauses and a request lands here. You approve, modify, or reject; the agent resumes with that decision.\n\nHow to use this page:\n\n1. Triage. Each card shows the agent, the tool, the arguments, and the reason approval was required. Use the filters to narrow by status (pending / approved / rejected / expired).\n\n2. Decide. \"Approve\" lets the call go through as-is. \"Modify\" lets you edit the arguments before approving (e.g. tighten the SQL WHERE clause). \"Reject\" cancels the call and returns an error to the agent.\n\n3. Bulk-handle. Select multiple pending requests and approve / reject in batch. Batch approve is disabled if you have TOTP enrolled (every approve must enter a fresh code).\n\n4. Enroll TOTP. Use the TOTP setup flow if your policy requires a second factor on approvals. Once enrolled, single approvals require a 6-digit code; batch approval is locked off.\n\nTypical scenarios:\n\n  · Letting an agent autonomously edit code but gating any `rm -rf` / `git push` behind a human eye.\n  · Catching the first time an agent tries to spend > $X on a single LLM call.\n  · Reviewing a queue of channel-bot replies before they go out, during a soak-test phase.\n\nThings to know:\n\n  · Pending requests have a TTL — if you don't decide in time they expire and the agent gets a \"rejected by timeout\" answer. The TTL is configurable in approvals policy.\n  · Modify is auditable: the diff between original and modified args is recorded.\n  · TOTP is per-operator. Enrolment and revocation are also audit-logged.",
    "selectAll": "Select All",
    "approveSelected": "Approve Selected",
    "rejectSelected": "Reject Selected",
    "selected": "{{count}} selected",
    "modify": "Modify",
    "modifyTitle": "Modify & Retry",
    "modifyPlaceholder": "Provide feedback for the agent to retry with...",
    "modifySubmit": "Submit Feedback",
    "modifiedToast": "Feedback submitted",
    "batchSuccess": "Batch action completed",
    "tabPending": "Pending",
    "tabAuditLog": "Audit Log",
    "auditLog": {
      "title": "Approval Audit Log",
      "tool": "Tool",
      "agent": "Agent",
      "decision": "Decision",
      "decidedBy": "Decided By",
      "decidedAt": "Decided At",
      "requestedAt": "Requested At",
      "feedback": "Feedback",
      "noEntries": "No audit entries found.",
      "showing": "Showing {{from}}-{{to}} of {{total}}"
    },
    "loadError": "Failed to load approvals. Check your connection.",
    "batch_disabled_totp": "Batch approve disabled when TOTP is enforced",
    "goToAgent": "Go to Agent",
    "totpPlaceholder": "000000 / 0000-0000",
    "totpLabel": "TOTP",
    "tabHistory": "History",
    "pendingCount": "{{count}} pending",
    "filter": "Filter",
    "filterPlaceholder": "Filter by agent, tool, or action…",
    "noFilterMatch": "No requests match this filter.",
    "autoRules": "Auto-rules",
    "timeAgo": {
      "seconds": "{{count}}s",
      "minutes": "{{count}}m",
      "hours": "{{count}}h",
      "days": "{{count}}d"
    },
    "totpBadge": "TOTP",
    "requestedAgo": "requested {{ago}} ago",
    "approveWithTotp": "Approve with TOTP",
    "editApprove": "Edit & approve",
    "editApproveTitle": "Edit and approve",
    "editApproveSubmit": "Submit & approve",
    "deny": "Deny",
    "risk": {
      "high": "high risk",
      "medium": "medium risk",
      "low": "low risk"
    },
    "history": {
      "empty": "No history yet",
      "emptyDesc": "Resolved approvals will appear here.",
      "decisions": {
        "approved": "Approved",
        "denied": "Denied",
        "edited": "Edited"
      },
      "cols": {
        "decision": "Decision",
        "agent": "Agent",
        "action": "Action",
        "risk": "Risk",
        "resolvedBy": "Resolved by",
        "when": "When"
      }
    },
    "totp": {
      "modalTitle": "Confirm with TOTP",
      "modalSubtitle": "High-risk action requires 2FA",
      "modalContext": "wants to run: {{action}}. Enter the 6-digit code from your authenticator (or a 8-digit recovery code).",
      "expiresHint": "Codes refresh every 30 seconds.",
      "confirm": "Confirm & approve"
    }
  },
  "wizard": {
    "welcome": "Welcome to LibreFang",
    "subtitle": "Connect a model provider and you're ready to chat, code, and orchestrate agents.",
    "step_1": "Step 1",
    "connect_provider": "Connect a Provider",
    "step_1_desc": "Pick an LLM provider to power your agents. You can add more later from the Providers page.",
    "add_api_key": "Add API Key",
    "step_2_desc": "Paste your {{provider}} API key. It is stored encrypted in the local vault.",
    "api_key_label": "API Key",
    "no_key_needed": "This provider does not require an API key — local or self-hosted.",
    "env_hint": "Tip: you can also export {{env}} in your environment; the wizard will pick it up automatically.",
    "provider_ready": "Ready",
    "needs_key": "Needs Key",
    "no_key": "No Key",
    "no_providers": "No providers loaded. Is the daemon running?",
    "already_configured": "Already configured",
    "already_configured_desc": "This provider already has a valid key. You can skip to the next step or replace the key below.",
    "provider_connected": "Provider connected successfully",
    "provider_failed": "Could not connect: {{message}}",
    "connect": "Connect & Test",
    "finish_title": "You're all set",
    "step_3_desc": "Confirm and we'll set this provider as default and initialize a starter agent.",
    "step_3_hint": "The starter agent uses a balanced model and safe defaults. You can tune everything from the Agents and Settings pages afterwards.",
    "summary_provider": "Provider",
    "summary_status": "Status",
    "finish_action": "Launch LibreFang",
    "finalize_failed": "Setup failed: {{message}}",
    "done_title": "LibreFang is ready",
    "done_desc": "Your default provider is configured and a starter agent has been created. You can now chat or jump into the dashboard.",
    "go_overview": "Go to Overview",
    "start_chat": "Start Chatting",
    "skip": "Skip wizard",
    "replace_key_warning": "This provider is already connected with a working key. Submitting will overwrite it — a failed test cannot restore the previous key. Check to acknowledge.",
    "api_key_placeholder": "sk-...",
    "model_count": "{{count}} models"
  },
  "models": {
    "section": "Infrastructure",
    "title": "Model Catalog",
    "subtitle": "Browse all available LLM models across providers.",
    "search_placeholder": "Search models...",
    "all_providers": "All Providers",
    "all_tiers": "All",
    "available_only": "Available Only",
    "available": "available",
    "availability": "Availability",
    "results": "models",
    "free": "Free",
    "no_results": "No models match your filters.",
    "no_models": "No models loaded. Is the daemon running?",
    "load_error": "Failed to load models. Check if the daemon is running.",
    "no_key": "No Key",
    "tier_all": "All",
    "tier_frontier": "Frontier",
    "tier_smart": "Smart",
    "tier_balanced": "Balanced",
    "tier_fast": "Fast",
    "tier_local": "Local",
    "tier_basic": "Basic",
    "tier_standard": "Standard",
    "tier_advanced": "Advanced",
    "tier_enterprise": "Enterprise",
    "col_model": "Model",
    "col_provider": "Provider",
    "col_tier": "Tier",
    "col_context": "Context",
    "col_input": "Input $/M",
    "col_output": "Output $/M",
    "col_tools": "Tools",
    "col_vision": "Vision",
    "col_streaming": "Streaming",
    "col_thinking": "Thinking",
    "help": "The model catalogue is this instance's view of every LLM model available across configured providers — IDs, capabilities (tools / vision / streaming / thinking), context window, input / output pricing, and tier. The catalogue feeds the model picker on every agent and the cost calculator on Analytics.\n\nHow to use this page:\n\n1. Filter & sort. Filter by provider, tier, or \"available only\" (excludes models whose provider isn't configured). Search by name / alias.\n\n2. Compare. Columns side-by-side: context, input price, output price, tools, vision, thinking. Pick what fits the workload before assigning to an agent.\n\n3. Add custom. \"Add custom model\" lets you register a model the catalogue doesn't ship with — useful for new releases or self-hosted endpoints. Provide ID, display name, provider, and pricing.\n\n4. Edit / delete. Tweak display name or pricing on existing entries. Deletion is for custom entries you added.\n\nTypical scenarios:\n\n  · Picking a vision-capable model for a screenshot-analysis agent.\n  · Registering a brand-new model the day it launches, before LibreFang ships an update.\n  · Auditing which models have tool-use vs. which don't, before assigning agents.\n\nThings to know:\n\n  · \"Available\" depends on whether the provider is configured and reachable. Configure it on Providers first.\n  · Pricing here is what the cost calculator believes — keep it accurate or budget figures drift.\n  · Aliases let you address one underlying model under multiple names (e.g. \"smart\" → claude-opus).",
    "add_model": "Add Model",
    "add_custom_model": "Add Custom Model",
    "model_id": "Model ID",
    "model_id_placeholder": "e.g. my-custom-model",
    "display_name": "Display Name",
    "display_name_placeholder": "e.g. My Custom Model",
    "provider": "Provider",
    "provider_placeholder": "e.g. openai",
    "context_window": "Context Window",
    "max_output": "Max Output Tokens",
    "input_cost": "Input Cost ($/M tokens)",
    "output_cost": "Output Cost ($/M tokens)",
    "supports_tools": "Tool Use",
    "supports_vision": "Vision",
    "supports_streaming": "Streaming",
    "supports_thinking": "Thinking",
    "custom": "Custom",
    "delete_model": "Delete custom model",
    "model_added": "Model added successfully",
    "model_deleted": "Model deleted",
    "hide_model": "Hide model",
    "unhide_model": "Unhide model",
    "show_hidden": "Hidden",
    "hidden_count": "{{count}} hidden",
    "model_hidden": "Model hidden",
    "model_unhidden": "Model unhidden",
    "expand_all": "Expand All",
    "collapse_all": "Collapse All",
    "aliases": "Aliases",
    "max_output_tokens": "Max Output",
    "cost_range": "Cost",
    "settings_title": "Model Settings",
    "model_type": "Model Type",
    "type_chat": "Chat",
    "type_speech": "Speech",
    "type_embedding": "Embedding",
    "capabilities": "Capabilities",
    "capabilities_override_hint": "Override capabilities when the provider's metadata is wrong, missing, or non-standard. \"Auto\" uses the catalog default.",
    "cap_auto": "Auto",
    "cap_force_on": "Force On",
    "cap_force_off": "Force Off",
    "cap_on": "on",
    "cap_off": "off",
    "parameters": "Parameters",
    "temperature": "Temperature",
    "top_p": "Top P",
    "max_tokens_param": "Max Tokens",
    "frequency_penalty": "Frequency Penalty",
    "presence_penalty": "Presence Penalty",
    "reasoning_effort": "Reasoning Effort",
    "effort_low": "Low",
    "effort_medium": "Medium",
    "effort_high": "High",
    "flags": "Flags",
    "use_max_completion_tokens": "Use max_completion_tokens",
    "no_system_role": "No System Role",
    "force_max_tokens": "Force Max Tokens",
    "overrides_saved": "Model settings saved",
    "overrides_reset": "Model settings reset to defaults",
    "overrides_error": "Failed to save model settings",
    "reset_defaults": "Reset"
  },
  "media": {
    "section": "Media",
    "title": "Media Generation",
    "subtitle": "Generate images, speech, videos, and music through configured providers.",
    "help": "Media generation is the cross-provider front-end for images, speech, video, and music. All endpoints share the same provider abstraction — pick a capability, optionally pick a provider, prompt, generate.\n\nHow to use this page:\n\n1. Pick a capability. Image / TTS / video / music tabs share the same shape: prompt, parameters, generate.\n\n2. Provider auto-detect. Leave provider on auto and the backend picks the first configured driver for that capability. Override only when you want a specific one.\n\n3. Tune parameters. Aspect ratio, count, format (wav / opus / flac / …), instrumental vs. vocal — each capability exposes the relevant knobs.\n\n4. Generate & download. Output appears inline; \"Download\" saves the file locally.\n\nTypical scenarios:\n\n  · Quick one-off image / voice generation without leaving the dashboard.\n  · Comparing the same prompt across providers by switching the provider drop-down.\n  · Generating short audio clips for use in a channel bot reply.\n\nThings to know:\n\n  · Cost lands on the same metering as LLM calls — large videos / music can be expensive.\n  · If \"auto\" returns \"no provider configured\", set one up on Providers first.\n  · Outputs live in the daemon's media dir; the dashboard streams them, but the source of truth is on disk.",
    "load_error": "Failed to load providers.",
    "configured": "Configured",
    "not_configured": "Not configured",
    "no_providers": "No media providers found.",
    "no_capabilities": "No capabilities",
    "cap_image": "Image",
    "cap_speech": "Speech",
    "cap_video": "Video",
    "cap_music": "Music",
    "tab_image": "Image",
    "tab_speech": "Speech",
    "tab_video": "Video",
    "tab_music": "Music",
    "provider": "Provider",
    "model": "Model",
    "model_placeholder": "Leave blank for default",
    "auto_detect": "Auto-detect",
    "prompt": "Prompt",
    "text": "Text",
    "voice": "Voice",
    "voice_placeholder": "e.g. alloy",
    "format": "Format",
    "speed": "Speed",
    "count": "Count",
    "aspect_ratio": "Aspect Ratio",
    "lyrics": "Lyrics",
    "music_prompt": "Style Prompt",
    "instrumental": "Instrumental",
    "instrumental_desc": "No vocals",
    "generate": "Generate",
    "synthesize": "Synthesize",
    "compose": "Compose",
    "generate_video": "Submit Video Task",
    "polling": "Polling...",
    "download": "Download",
    "result": "Result",
    "status": "Status",
    "task_id": "Task ID",
    "revised_prompt": "Revised prompt",
    "image_title": "Image Generation",
    "image_desc": "Generate images from text descriptions.",
    "image_prompt_placeholder": "Describe the scene you want...",
    "image_done": "Image generated",
    "speech_title": "Text-to-Speech",
    "speech_desc": "Synthesize text into natural-sounding audio.",
    "speech_text_placeholder": "Text to synthesize...",
    "speech_done": "Speech synthesized",
    "video_title": "Video Generation",
    "video_desc": "Video generation is asynchronous — the result is polled after submission.",
    "video_prompt_placeholder": "Describe the video content...",
    "video_submitted": "Video task submitted",
    "video_done": "Video generation complete",
    "video_polling": "Task in progress, polling every 5 seconds...",
    "music_title": "Music Generation",
    "music_desc": "Compose music from a style prompt or lyrics.",
    "music_prompt_placeholder": "e.g. 'Upbeat pop piano'...",
    "lyrics_placeholder": "Enter lyrics (optional)...",
    "music_done": "Music generated",
    "no_provider_image": "No provider configured for image generation",
    "no_provider_speech": "No provider configured for text-to-speech",
    "no_provider_video": "No provider configured for video generation",
    "no_provider_music": "No provider configured for music generation",
    "aspect_ratio_placeholder": "1:1",
    "generated_alt": "generated {{index}}",
    "format_mp3": "mp3",
    "format_wav": "wav",
    "format_flac": "flac",
    "format_ogg": "ogg",
    "format_opus": "opus",
    "format_aac": "aac",
    "status_submitted": "submitted",
    "status_completed": "completed",
    "status_failed": "failed"
  },
  "auth": {
    "title": "API Key Required",
    "description": "This instance requires authentication to access.",
    "credentials_title": "Sign In Required",
    "credentials_description": "Enter your dashboard username and password to continue.",
    "credentials_tab": "Password",
    "api_key_tab": "API Key",
    "placeholder": "Enter API key...",
    "username_placeholder": "Enter username...",
    "password_placeholder": "Enter password...",
    "submit": "Authenticate",
    "verify_totp": "Verify",
    "totp_prompt": "Enter the 6-digit code from your authenticator app.",
    "invalid": "Authentication failed. Please try again.",
    "invalid_api_key": "Invalid API key. Please try again.",
    "invalid_credentials": "Invalid username or password. Please try again.",
    "invalid_totp": "Invalid TOTP code. Please try again."
  },
  "network": {
    "section": "OFP Network",
    "title": "Network",
    "subtitle": "Open Federation Protocol network status and connected peers.",
    "status_label": "Status",
    "node_id": "Node ID",
    "protocol": "Protocol",
    "peers": "Connected Peers",
    "connected": "connected",
    "no_peers": "No peers connected",
    "no_peers_desc": "No OFP peers are currently connected to this node.",
    "identity_fingerprint": "Identity fingerprint",
    "identity_fingerprint_hint": "Compare with the remote operator out-of-band before pinning.",
    "identity_missing": "No Ed25519 identity loaded. OFP is running in HMAC-only legacy mode; per-peer impersonation defense (#3873) is dormant.",
    "pinned_peers_count_one": "{{count}} TOFU-pinned peer",
    "pinned_peers_count_other": "{{count}} TOFU-pinned peers",
    "trusted_peers": "Trusted peers",
    "trusted_peers_pinned": "{{count}} pinned",
    "trusted_peer_fingerprint_hint": "SHA-256 fingerprint of the pinned Ed25519 public key. Compare OOB.",
    "no_trusted_peers": "No trusted peers",
    "no_trusted_peers_desc": "No peers have been TOFU-pinned to this node's identity yet. Pin a peer's fingerprint to enable per-peer impersonation defense (#3873).",
    "ofp_disabled": "OFP networking is not enabled. Set `network_enabled = true` and a non-empty `shared_secret` in config.toml. The Ed25519 identity is generated and persisted automatically on first start.",
    "help": "Network shows this instance's status in the Open Federation Protocol (OFP) — peer LibreFang nodes you've discovered or been discovered by, your own node identity, and the OFP version in use. OFP is the layer below A2A: it's how nodes find each other; A2A is what they say once connected.\n\nHow to use this page:\n\n1. Identity. The node-id and protocol version identify this LibreFang instance to the federation.\n\n2. Peers. Shows every connected peer with online / offline status. Empty list means you're not federating with anyone yet.\n\n3. Status. Online means OFP is reachable and your node is announcing itself.\n\nWhen to use it (vs. A2A):\n\n  · Network — node-level federation: who's out there, who's connected.\n  · A2A — agent-level talk: what agents on those nodes can do for each other.\n\nTypical scenarios:\n\n  · Confirming two LibreFang instances actually see each other before debugging A2A.\n  · Reading off your node-id to share with a peer for direct connection.\n\nThings to know:\n\n  · Federation is opt-in and config-gated. If \"no peers\" looks empty by default, that's expected unless you've configured peers.\n  · Network status is a live read — refresh polls, no caching."
  },
  "a2a": {
    "section": "Agent-to-Agent",
    "title": "A2A",
    "subtitle": "Discover and communicate with external A2A agents.",
    "discover": "Discover",
    "discover_agent": "Discover Agent",
    "discover_placeholder": "https://example.com/.well-known/agent.json",
    "external_agents": "External Agents",
    "no_agents": "No external agents",
    "no_agents_desc": "Discover A2A agents by entering their URL.",
    "send_task": "Send Task",
    "send_to": "Send task to",
    "task_placeholder": "Describe the task for this agent...",
    "send": "Send",
    "tracked_tasks": "Tracked Tasks",
    "status_pending": "Pending",
    "status_completed": "Completed",
    "status_failed": "Failed",
    "status_working": "Working",
    "help": "A2A (Agent-to-Agent) is an open protocol from Google that lets independent agent runtimes discover and call each other. Every A2A agent publishes an \"agent card\" at /.well-known/agent.json describing its name, skills, and how to send it tasks. LibreFang serves its own card at the same path, so other A2A clients can discover this instance too.\n\nHow to use this page:\n\n1. Discover. Click \"Discover\" (shortcut: n) and paste the URL of an external agent (e.g. https://example.com/agents/research-bot). LibreFang fetches /.well-known/agent.json and adds it to \"External agents\" with its skills and availability.\n\n2. Send a task. On any agent card, click \"Send task\", type a natural-language instruction, and submit. LibreFang sends a JSON-RPC task and gets back a task_id. The new task appears under \"Tracked tasks\".\n\n3. Track. Click \"Refresh\" on a tracked task to poll its status: pending → completed / failed. The result text shows up inline when the remote agent finishes.\n\nWhen to use it (vs. Channels and MCP):\n\n  · Channels — a person talks to your agent via Telegram / Slack / etc. Direction: human → agent.\n  · MCP — your agent calls an external tool server. Direction: agent → tool.\n  · A2A — your agent talks to someone else's agent as a peer. Direction: agent ↔ agent.\n\nTypical scenarios:\n\n  · Two LibreFang instances (yours + a teammate's, or home + work) cooperating on tasks.\n  · Subscribing to a public A2A agent that specialises in something — e.g. a research / translation / search agent — and forwarding suitable tasks to it.\n  · Splitting a fleet of internal LibreFang instances by domain expertise and routing between them.\n\nThings to know:\n\n  · The \"Tracked tasks\" list lives only in your browser — refreshing the page drops it. The remote side keeps its own task store; save the task_id if you need to look it up later.\n  · LibreFang's SSRF protection blocks discovery of localhost / private-network URLs by default. To discover an agent on your LAN, add its host to ssrf_allowed_hosts in config.toml.\n  · The A2A ecosystem is still young — public A2A endpoints are rare today. The most concrete way to try this page is to point another LibreFang instance at this one and discover both ways."
  },
  "plugins": {
    "section": "Extensions",
    "title": "Plugins",
    "subtitle": "Extend agent capabilities with custom plugins.",
    "new_plugin": "New Plugin",
    "install": "Install",
    "installed_tab": "Installed",
    "registry_tab": "Marketplace",
    "no_plugins": "No plugins installed",
    "no_plugins_desc": "Install plugins from the marketplace or create your own.",
    "loading_registries": "Loading marketplace...",
    "no_registries": "No marketplace configured.",
    "no_available": "No plugins available.",
    "installed": "Installed",
    "plugin_name": "Plugin Name",
    "description": "Description",
    "install_title": "Install Plugin",
    "source": "Source",
    "source_registry": "Marketplace",
    "source_local": "Local",
    "source_git": "Git",
    "registry_optional": "Registry (optional)",
    "registry_placeholder": "owner/repo",
    "path": "Path",
    "url": "URL",
    "branch": "Branch",
    "scaffold_title": "Create New Plugin",
    "scaffold_desc": "What does this plugin do?",
    "create": "Create",
    "deps": "Deps",
    "help": "Plugins are runtime extensions — code you (or someone else) wrote that hooks into the kernel and adds tools, hooks, or behaviour beyond what ships in core. Different from skills (declarative capability docs) and hands (managed bundles): a plugin is raw code with full access to the runtime.\n\nHow to use this page:\n\n1. Browse. The \"Installed\" tab lists active plugins with version, hooks, dependencies, size, and metadata. The marketplace tab lists ones you can install.\n\n2. Install. \"Install\" pulls from the marketplace, a local path, or a Git repository / branch. Dependency install runs as part of the flow; the result panel shows success or the failing step.\n\n3. Inspect. Click a plugin to see its hooks, deps, and metadata. Useful when debugging which plugin owns a tool name.\n\n4. Remove. Delete uninstalls — removes the plugin code and unhooks anything it registered.\n\nTypical scenarios:\n\n  · Adding a custom plugin that exposes your internal API as agent tools.\n  · Pulling a community plugin from a Git URL, branch-pinned to a known-good commit.\n  · Removing a plugin that conflicts with another for the same tool name.\n\nThings to know:\n\n  · Plugins run with daemon privileges — only install ones you trust.\n  · Installing from Git locks to a branch; redeploy by re-installing if the upstream branch moves.\n  · A failing dependency install leaves the plugin in an invalid state — the panel shows what's missing.",
    "deps_failed": "Dependency install failed",
    "deps_installed": "Dependencies installed",
    "install_failed": "Install failed",
    "install_success": "Plugin installed",
    "no_description": "No description provided.",
    "runtime": "Runtime",
    "scaffold_failed": "Create failed",
    "scaffold_success": "Plugin created",
    "uninstall_failed": "Uninstall failed",
    "uninstall_success": "Plugin removed",
    "invalid": "Invalid",
    "hooks": "Hooks",
    "hook_ingest": "Ingest",
    "hook_after_turn": "After Turn",
    "hook_invalid": "Invalid",
    "runtime_python": "Python",
    "runtime_node": "Node.js",
    "runtime_deno": "Deno (TypeScript)",
    "runtime_bun": "Bun (TypeScript)",
    "runtime_go": "Go",
    "runtime_v": "V (vlang)",
    "runtime_ruby": "Ruby",
    "runtime_php": "PHP",
    "runtime_lua": "Lua",
    "runtime_bash": "Bash",
    "runtime_native": "Native binary"
  },
  "schema_form": {
    "select_option": "Select...",
    "comma_separated": "Comma-separated values",
    "add_item": "Add",
    "load_error": "Failed to load form schema",
    "required_missing": "Please fill in all required fields",
    "from_schema": "From Schema"
  },
  "command_palette": {
    "search_placeholder": "Search pages...",
    "navigate": "Navigate",
    "open": "Open",
    "close": "Close",
    "registry": "Registry (librefang.ai)",
    "all_shortcuts": "all shortcuts"
  },
  "terminal": {
    "badge": "Terminal",
    "title": "Terminal",
    "subtitle_connected": "Connected",
    "subtitle_disconnected": "Disconnected",
    "subtitle_connecting": "Connecting…",
    "subtitle_reconnecting": "Reconnecting… ({{attempt}}/{{max}})",
    "subtitle_error": "Error: {{error}}",
    "connect": "Connect",
    "disconnect": "Disconnect",
    "started": "[Terminal started: {{shell}} (PID: {{pid}})]",
    "exited": "[Process exited with code {{code}}]",
    "error_unknown": "Unknown error",
    "websocket_error": "WebSocket connection error",
    "connection_closed_non_recoverable": "Connection closed due to a non-recoverable error",
    "max_reconnect_exceeded": "Max reconnection attempts reached. Please connect manually.",
    "fast_exit_giveup": "Terminal launch failed — the shell could not start (or exited immediately). Check the daemon host's shell binary, TERM / terminfo (the `xterm-256color` entry must be installed: `ncurses-term` on Debian/Ubuntu, `ncurses-terminfo-base` on Alpine, `ncurses-base` on RHEL/Fedora) and tmux configuration; reconnecting won't help until the underlying error is fixed.",
    "root_warning": "Warning: The daemon is running as root. Terminal commands execute with full privileges.",
    "enter_fullscreen": "Enter fullscreen",
    "exit_fullscreen": "Exit fullscreen (Esc)",
    "dismiss_error": "Dismiss",
    "search_placeholder": "Search… (Enter: next, Shift+Enter: prev)",
    "search_prev": "Previous match",
    "search_next": "Next match",
    "search_close": "Close search",
    "font_decrease": "Decrease font size",
    "font_increase": "Increase font size",
    "copy_paste_hint": "Tip: use Ctrl+Shift+C / Ctrl+Shift+V to copy and paste in the terminal",
    "tabs": {
      "new": "New tab",
      "unnamed": "Unnamed",
      "close": "Close tab",
      "limit_reached": "Window limit reached",
      "switch_failed": "Failed to switch window",
      "create_failed": "Failed to create window",
      "delete_failed": "Failed to close window",
      "rename_failed": "Failed to rename window",
      "rename_hint": "Double-click to rename",
      "tmux_unavailable": "tmux is not available on this host",
      "name_label": "Window name",
      "name_invalid": "Name must be 1–64 characters and cannot contain | or control characters.",
      "counter": "{{used}} / {{total}}",
      "help": "Keyboard shortcuts",
      "help_title": "Tab shortcuts",
      "help_switch": "Switch tab",
      "help_switch_key": "Click",
      "help_rename": "Rename tab",
      "help_rename_key": "Double-click",
      "help_close": "Close tab",
      "help_close_key": "Middle-click / ✕",
      "help_new": "New tab",
      "help_new_key": "＋"
    },
    "install_tmux": "Install tmux",
    "reconnected": "Reconnected"
  },
  "mcp": {
    "badge": "MCP",
    "title": "MCP Servers",
    "subtitle": "Manage Model Context Protocol server connections",
    "empty": "No MCP servers configured",
    "empty_desc": "Add an MCP server to extend agent capabilities with external tools.",
    "add_server": "Add Server",
    "edit_server": "Edit Server",
    "delete_server": "Delete Server",
    "delete_confirm": "Are you sure you want to delete this MCP server? This action cannot be undone.",
    "name": "Name",
    "name_placeholder": "my-server",
    "transport_type": "Transport",
    "command": "Command",
    "command_placeholder": "npx",
    "args": "Arguments",
    "args_placeholder": "One argument per line",
    "add_argument": "Add argument",
    "remove_argument": "Remove argument",
    "url": "URL",
    "url_placeholder": "http://localhost:3000/sse",
    "timeout": "Timeout (seconds)",
    "env": "Environment Variables",
    "env_placeholder": "KEY=VALUE",
    "add_variable": "Add variable",
    "remove_variable": "Remove variable",
    "headers": "Headers",
    "headers_placeholder": "Header: value (one per line)",
    "connected": "Connected",
    "disconnected": "Disconnected",
    "tools": "Tools",
    "tools_count": "{{count}} tools",
    "no_tools": "No tools",
    "configured": "Configured",
    "total_configured": "{{count}} configured",
    "total_connected": "{{count}} connected",
    "add_success": "MCP server added",
    "add_failed": "Failed to add MCP server",
    "update_success": "MCP server updated",
    "update_failed": "Failed to update MCP server",
    "delete_success": "MCP server deleted",
    "delete_failed": "Failed to delete MCP server",
    "show_tools": "Show tools",
    "hide_tools": "Hide tools",
    "help": "MCP (Model Context Protocol) servers are external tool providers your agents can call. The protocol standardises tool-discovery and tool-invocation, so any MCP-compliant server becomes available to agents on this instance once added.\n\nSupported transports:\n  · stdio — runs a local command (e.g. `npx`, `python`)\n  · SSE — connects via Server-Sent Events\n  · HTTP — connects via HTTP Streamable\n\nHow to use this page:\n\n1. Install from catalogue. Browse the catalogue tab and click \"Install\" on a known server. The transport, args, and env are pre-filled.\n\n2. Add custom. \"Add server\" lets you wire any MCP server — pick the transport, provide the command / URL, fill args and env vars.\n\n3. Authenticate. Servers that need OAuth show \"Authorize\"; click it to start the PKCE flow. Re-authorize when tokens expire; revoke to cut access.\n\n4. Verify. After add / connect, the server card lists its tools. Agents can now request them via tool policy.\n\nTypical scenarios:\n\n  · Plugging in a filesystem MCP so agents can read and write a sandbox dir.\n  · Wiring a SaaS MCP (Notion, Linear, …) for ticket / doc workflows.\n  · Running an internal MCP server that exposes your business APIs.\n\nThings to know:\n\n  · OAuth flow is UI-driven — daemon detects 401, the API server runs PKCE and the callback. Dynamic Client Registration (RFC 7591) is used when the server supports it.\n  · Env-var values are stored as configured; treat them as secrets.\n  · A failing server keeps showing in the list as auth-pending / failed; check the auth and transport before debugging tools.",
    "auth_authorized": "Authorized",
    "auth_pending": "Authorizing...",
    "auth_authorize": "Authorize",
    "auth_reauthorize": "Re-authorize",
    "auth_revoke": "Revoke",
    "auth_started": "Authorization started — complete in the new tab",
    "auth_revoked": "Authorization revoked",
    "auth_failed": "Auth failed",
    "auth_start_failed": "Failed to start auth",
    "auth_revoke_failed": "Failed to revoke auth",
    "tab_my_servers": "Servers",
    "tab_catalog": "MCP Marketplace",
    "catalog_subtitle": "Browse and install pre-configured MCP server templates",
    "catalog_empty": "No MCP server templates available",
    "catalog_empty_desc": "MCP server templates will appear after a registry sync.",
    "catalog_installed": "Installed",
    "catalog_install": "Install",
    "catalog_search_placeholder": "Search MCP servers...",
    "reload": "Reload",
    "reload_success": "MCP servers reloaded",
    "reload_failed": "Failed to reload MCP servers",
    "health_ok": "Healthy",
    "health_degraded": "Degraded",
    "search_placeholder": "Search servers...",
    "filter_all": "All",
    "filter_connected": "Connected",
    "filter_disconnected": "Disconnected",
    "no_results": "No matching servers",
    "no_results_desc": "Try a different search term or filter.",
    "show_more_tools": "Show {{count}} more...",
    "stdio_config": "Stdio Configuration",
    "connection": "Connection",
    "url_hint": "URL must start with http:// or https://",
    "env_setup_title": "Configure {{name}}",
    "env_setup_desc": "Enter the required API keys and environment variables to complete the installation.",
    "requires_env_count_one": "{{count}} key",
    "requires_env_count_other": "{{count}} keys",
    "wizard": {
      "eyebrow": "install · mcp server",
      "step_permissions": "Overview",
      "step_configure": "Configure",
      "step_installing": "Installing",
      "step_done": "Done",
      "requires": "Requires",
      "get_credential": "Get credential",
      "review_notice": "After install, the server's tools start gated by the approval policy — destructive calls require human sign-off until you scope them down.",
      "confirm_review": "I've reviewed what this server can do.",
      "creds_note": "Credentials are encrypted in the local vault and only released to this server's process at connect-time.",
      "installing": "Installing {{name}}…",
      "installing_sub": "Persisting config, registering with the runtime.",
      "done_title": "Installed",
      "done_body": "{{name}} is connected and exposing its tools to your agents.",
      "view_servers": "View servers"
    },
    "edit_taint_policy": "Taint policy",
    "taint_policy_short": "Taint",
    "taint_policy_title": "Taint policy — {{name}}",
    "taint_policy_saved": "Taint policy saved",
    "taint_policy_save_failed": "Failed to save taint policy",
    "taint_scanning_label": "Outbound taint scanning",
    "taint_scanning_help": "When off, no content heuristic runs on this server's tool arguments. Key-name blocking and the per-tool rules below still apply when on.",
    "taint_scanning_off_warning": "Per-tool exemptions below are ignored while server-level scanning is off. Re-enable scanning to use the granular policy.",
    "taint_tools_heading": "Per-tool exemptions",
    "taint_add_tool": "Add tool policy",
    "taint_remove_tool": "Remove tool policy",
    "taint_no_tool_policies": "No per-tool exemptions yet. Add one to skip individual rules for known-safe arguments.",
    "taint_tool": "tool",
    "taint_paths_heading": "Path exemptions",
    "taint_add_path": "Add path",
    "taint_remove_path": "Remove path exemption",
    "taint_no_paths": "No path exemptions. The full rule set applies to every argument.",
    "taint_default_skip_hint": "default = skip — argument paths below are ignored because scanning is bypassed for this tool.",
    "taint_skip_rule_sets_hint": "default = skip bypasses scanning entirely — rule_sets above will not fire (not even Log). Switch to default = scan for audit-only rule sets.",
    "taint_rule_sets_placeholder": "comma-separated names from [[taint_rules]]",
    "taint_rule_sets_overlap_hint": "When sets overlap on the same rule, the most permissive action wins (log > warn > block) — an audit-only set will silently neutralise a block set on the shared rule.",
    "taint_rule_sets_unknown_hint": "Unknown rule_set name(s): {{names}} — not defined in any [[taint_rules]]. The scanner will treat them as no-ops.",
    "view_detail": "View server details",
    "transport": "Transport",
    "required_env": "Required environment",
    "setup_instructions": "Setup",
    "taint_rule_label": {
      "authorization_literal": "Blocks `Authorization:` header prefix",
      "key_value_secret": "Blocks `key=value` / `key: value` secret shapes",
      "well_known_prefix": "Blocks `sk-` / `ghp_` / `AKIA` / `AIza` prefixes",
      "opaque_token": "Blocks long mixed-alnum opaque tokens",
      "pii_email": "Blocks e-mail addresses",
      "pii_phone": "Blocks phone numbers",
      "pii_credit_card": "Blocks credit-card numbers",
      "pii_ssn": "Blocks Social Security numbers",
      "sensitive_key_name": "Blocks JSON keys named `authorization`/`api_key`/..."
    }
  },
  "toml_viewer": {
    "tab_toml": "TOML",
    "tab_markdown": "Markdown",
    "copy": "Copy to clipboard",
    "copied": "Copied to clipboard",
    "copy_failed": "Failed to copy",
    "download": "Download",
    "loading": "Loading…"
  },
  "audit": {
    "title": "Audit trail",
    "subtitle": "Searchable, filterable audit log across users / actions / agents.",
    "help": "The audit trail is a hash-chained, tamper-evident log of every privileged action this instance has taken — agent spawns, approvals, config changes, RBAC edits, key rotations, etc. Each row is linked to the previous via a SHA hash, so any retroactive edit to old rows breaks the chain and is detectable.\n\nHow to use this page:\n\n1. Filter. Narrow by user, agent, action type, channel, or time range. Filters operate on an in-memory window (server hard cap 5000 rows); deeper history needs an export.\n\n2. Inspect. Click a row to see the full payload, hash, previous-hash, and timestamp. Copy hash / JSON / link-to-row from the detail panel for incident reports.\n\n3. Verify. The Runtime page has an \"Audit verify\" button that walks the chain and reports valid / invalid. Run it after a suspicious event or before exporting evidence.\n\n4. Export. CSV is for reporting; JSON keeps the full payload + hashes so you can verify the chain offline (or feed it into an external SIEM).\n\nTypical scenarios:\n\n  · Post-incident: who approved the destructive call at 03:14 UTC, with what arguments?\n  · Compliance: monthly export of all RBAC and config changes.\n  · Forensics: detect that a row was tampered with, by re-verifying the chain offline.\n\nThings to know:\n\n  · The hard 5000-row in-memory cap is a hot-window guardrail, not the storage limit. Older rows are still on disk; export pulls from disk.\n  · Filters narrow the displayed rows but don't change the chain — verification always runs over the full chain.\n  · Don't redact rows in-place. Hash chain integrity depends on every byte of every row staying byte-identical to when it was written.",
    "export_csv": "Export CSV",
    "exporting": "Exporting…",
    "export_error_title": "Export failed",
    "filters": "Filters",
    "quick_range": "Quick range",
    "clear_all": "Clear all",
    "reset": "Reset",
    "apply": "Apply filters",
    "f_user": "User",
    "f_user_placeholder": "UUID or name",
    "f_action": "Action",
    "f_agent": "Agent",
    "f_agent_placeholder": "agent id",
    "f_channel": "Channel",
    "f_channel_placeholder": "api / telegram / …",
    "f_from": "From",
    "f_to": "To",
    "any": "(any)",
    "forbidden_title": "Admin role required",
    "forbidden_body": "/api/audit/query is admin-only. Sign in with an Admin or Owner api_key.",
    "error_title": "Failed to load audit log",
    "empty_title": "No matching audit entries",
    "empty_filtered": "Try widening the filters, or clear them to see the most recent rows.",
    "empty_unfiltered": "Nothing recorded yet. As soon as agents take privileged actions they appear here.",
    "filter_by_action": "Filter by {{action}}",
    "filter_by_user": "Filter by this user",
    "filter_by_channel": "Filter by this channel",
    "filter_by_agent": "Filter by this agent",
    "hash_tooltip": "chain hash {{hash}}",
    "show_more": "Show more",
    "show_less": "Show less",
    "today": "Today",
    "yesterday": "Yesterday",
    "unknown_date": "Unknown",
    "range_custom": "Custom…",
    "export_json": "JSON",
    "export_csv_short": "CSV",
    "detail_title": "Audit entry",
    "detail_seq": "Sequence",
    "detail_timestamp": "Timestamp",
    "detail_action": "Action",
    "detail_outcome": "Outcome",
    "detail_agent": "Agent",
    "detail_user": "User",
    "detail_channel": "Channel",
    "detail_payload": "Detail",
    "detail_hash": "Hash",
    "detail_prev_hash": "Previous hash",
    "detail_copy_json": "Copy as JSON",
    "detail_copy_hash": "Copy hash",
    "detail_copy_link": "Copy permalink",
    "detail_copied": "Copied",
    "open_detail": "Open details",
    "preset_1h": "1h",
    "preset_24h": "24h",
    "preset_today": "Today",
    "preset_7d": "7d",
    "preset_30d": "30d"
  },
  "users": {
    "title": "Users & RBAC",
    "subtitle": "Manage operator accounts, channel bindings, and bulk-onboard via CSV.",
    "badge": "Phase 4 / M6",
    "help": "Users & RBAC manages operator accounts and external identities — every row is a person or a service account, with one or more channel bindings (Telegram / Discord / Slack / email) mapped to a LibreFang role (admin / operator / viewer / …). API keys for programmatic access are issued here too. Admin-only.\n\nHow to use this page:\n\n1. Create. \"Create user\" → fill ID, name, role; optionally add channel bindings and an API key. Save.\n\n2. Edit. Click a row to update role, add / remove bindings, set per-user budget / memory / policy hints (badges on the row show which are set).\n\n3. Bulk onboard. \"Paste CSV\" lets you import many users at once — useful for first-day onboarding of a team.\n\n4. Rotate / revoke. Rotate API key with the rotate flow (old key invalidated immediately). Delete removes the user and all their bindings.\n\nTypical scenarios:\n\n  · Adding a teammate so their Slack DMs route as themselves with the right role.\n  · Issuing an API key to a CI bot for programmatic agent calls.\n  · Bulk onboarding a class / cohort via CSV.\n\nThings to know:\n\n  · Rotate is destructive to in-flight clients — they get 401 immediately. Coordinate before rotating production keys.\n  · Channel bindings are unique per (channel, identity) — the same Telegram id can't map to two LibreFang users.\n  · Per-user policy / budget overrides are stored separately; the badges on the row tell you which a user has.",
    "simulator_link": "Permission simulator",
    "import_csv": "Bulk import (CSV)",
    "create": "New user",
    "create_title": "New user",
    "edit_title": "Edit user",
    "search_label": "Search",
    "search_placeholder": "Name or platform_id…",
    "role_filter_label": "Role",
    "all_roles": "All roles",
    "role_label": "Role",
    "name_label": "Name",
    "bindings_label": "Channel bindings",
    "bindings_empty": "No bindings. Use the identity wizard for guided platform_id formats.",
    "bindings_suffix": "channel binding(s)",
    "empty_title": "No users yet",
    "empty_desc": "Add a user, then link a platform identity so chat events get attributed to a real role.",
    "api_key": "API key",
    "has_policy_badge": "Policy",
    "has_policy_title": "User has a per-user tool policy / categories / channel rules override.",
    "has_memory_badge": "Memory",
    "has_memory_title": "User has a custom memory namespace ACL.",
    "has_budget_badge": "Budget",
    "has_budget_title": "User has a per-user spend cap configured.",
    "link": "Link identity",
    "rotate_key": "Rotate API key",
    "rotate_key_confirm": "Rotate now",
    "view_budget": "Budget →",
    "view_policy": "Permissions →",
    "user": "User",
    "confirm_delete_title": "Delete user?",
    "confirm_delete_body": "This removes the user from config.toml and rebuilds the RBAC channel index. Any platform identity that mapped to this user will fall through to the default-deny path.",
    "confirm_rotate_title": "Rotate API key?",
    "confirm_rotate_body": "Generates a fresh API key for this user. The old key stops working immediately — any client still using it will start receiving 401 errors on the next request. The new plaintext key will be shown ONCE on the next screen; the server cannot reproduce it later.",
    "rotate_key_error_title": "Rotation failed",
    "rotate_key_done_title": "New API key — copy now",
    "rotate_key_done_warning": "This is the ONLY time the plaintext key will be shown. Copy and store it now — the server cannot reproduce it later.",
    "rotate_key_done_user": "User",
    "rotate_key_done_close": "I've copied the key",
    "err_name_required": "Name is required.",
    "err_id_required": "platform_id is required.",
    "wizard_title": "Link a platform identity",
    "wizard_step1": "User",
    "wizard_step2": "Platform",
    "wizard_step3": "Identifier",
    "wizard_step4": "Confirm",
    "wizard_user_desc": "We'll add a binding to this user. The wizard never creates new users — pick a different user from the list to retarget.",
    "wizard_platform": "Platform",
    "wizard_platform_desc": "Pick which platform's identifier you're linking.",
    "wizard_id_desc": "Paste the platform's identifier. The format hint matches the channel you picked.",
    "wizard_id_label": "platform_id",
    "wizard_example": "Example",
    "wizard_confirm_desc": "Confirm and write to config.toml. The kernel rebuilds its RBAC channel index in place — no restart needed.",
    "wizard_unverified_title": "No automated ownership check",
    "wizard_unverified_body": "LibreFang does not yet ping the platform to confirm this id belongs to {{user}}. Anyone with Owner rights can bind any id to any user row, which silently retargets future RBAC and rate-limit decisions. Verify the platform_id with the user out-of-band before saving.",
    "wizard_unverified_ack": "I have verified out-of-band that {{platformId}} belongs to {{user}}.",
    "wizard_ack_required": "Acknowledge the ownership warning to save.",
    "wizard_commit": "Save binding",
    "csv_read_failed": "Could not read file — try pasting the contents instead.",
    "csv_paste": "Or paste CSV",
    "csv_drop": "Drop a CSV here, or click to browse.",
    "import_title": "Bulk import users",
    "import_desc": "Drop a CSV with columns name,role,telegram,discord,slack,email. Roles must be one of owner / admin / user / viewer.",
    "import_preview": "Preview",
    "import_dry_summary": "Dry-run summary",
    "import_summary": "Import complete",
    "import_dry_run": "Dry run",
    "import_commit": "Commit",
    "import_bindings_count": "{{count}} bindings",
    "import_result_counts": "{{created}} created · {{updated}} updated · {{failed}} failed",
    "import_row_error": "row {{row}} ({{name}}): {{error}}",
    "roles": {
      "owner": "Owner",
      "admin": "Admin",
      "user": "User",
      "viewer": "Viewer"
    },
    "platforms": {
      "telegram": {
        "label": "Telegram",
        "hint": "Numeric Telegram user ID (visible via @userinfobot).",
        "example": "123456789"
      },
      "discord": {
        "label": "Discord",
        "hint": "Numeric Discord user ID (right-click → Copy User ID, dev mode).",
        "example": "987654321098765432"
      },
      "slack": {
        "label": "Slack",
        "hint": "Slack member ID (Profile → More → Copy member ID).",
        "example": "U01ABCDEFGH"
      },
      "email": {
        "label": "Email",
        "hint": "Sender email address (used by IMAP / Mailgun channels).",
        "example": "alice@example.com"
      },
      "wechat": {
        "label": "WeChat",
        "hint": "WeCom / WeChat OpenID for the configured corp.",
        "example": "abc123@im.wechat"
      }
    },
    "row_actions": "More actions",
    "view_budget_chip": "Budget",
    "view_policy_chip": "Permissions",
    "rotate_key_only_chance": "This is your only chance to copy this key. Closing this dialog will discard the plaintext — the server cannot reproduce it.",
    "rotate_key_must_copy": "Click Copy first. The Close button unlocks once the key is on your clipboard.",
    "rotate_key_failed_toast": "Rotation failed: {{message}}",
    "rotate_key_copy_failed": "Copy failed — select the key and copy it manually before closing.",
    "rotate_key_copied_confirm": "Copied — you can close now",
    "csv_drop_aria": "Upload CSV file: drop here or activate to browse",
    "csv_paste_placeholder": "alice,user,telegram=123456789;email=alice@example.com",
    "wizard_step_platform": "Platform",
    "wizard_step_identity": "Identifier",
    "wizard_user_chip": "Linking identity to",
    "wizard_show_warning": "Why this matters",
    "wizard_hide_warning": "Hide warning",
    "wizard_step_back_aria": "Go back to step {{n}}"
  },
  "userBudget": {
    "fields": {
      "max_hourly": "Max hourly USD",
      "max_daily": "Max daily USD",
      "max_monthly": "Max monthly USD",
      "alert_threshold": "Alert threshold (0–1)"
    },
    "errors": {
      "non_negative": "{{field}} must be a finite, non-negative number",
      "threshold_range": "alert_threshold must be in 0.0..=1.0"
    },
    "toast": {
      "saved": "Spend cap saved"
    }
  },
  "userPolicy": {
    "toggle": {
      "configured": "Configured",
      "not_set": "Not set"
    },
    "errors": {
      "empty_entry": "{{field}} contains an empty entry",
      "duplicate_entry": "{{field}} contains duplicate entry '{{item}}'",
      "writable_not_subset": "memory_access.writable_namespaces['{{ns}}'] is not in readable_namespaces (writable must be a subset of readable)"
    },
    "discard": "Discard changes",
    "no_changes": "No unsaved changes",
    "unsaved_changes": "You have unsaved changes",
    "save_disabled_invalid": "Fix validation errors above to enable Save",
    "discard_confirm_title": "Discard unsaved changes?",
    "discard_confirm_body": "This reverts every field to the last server-loaded value. Edits made since the last save will be lost."
  },
  "permissionSimulator": {
    "status": {
      "configured": "Configured",
      "not_configured": "Not configured"
    },
    "budget": {
      "unlimited_window": "unlimited on window"
    },
    "actions": {
      "ChatWithAgent": {
        "label": "Chat with agent",
        "description": "Send messages to a running agent."
      },
      "ViewConfig": {
        "label": "View configuration",
        "description": "Read kernel config (redacted secrets)."
      },
      "ViewUsage": {
        "label": "View usage / billing",
        "description": "Inspect token / cost dashboards."
      },
      "SpawnAgent": {
        "label": "Spawn agent",
        "description": "Create and start a new agent process."
      },
      "KillAgent": {
        "label": "Kill agent",
        "description": "Stop a running agent."
      },
      "InstallSkill": {
        "label": "Install skill",
        "description": "Install ClawHub / Skillhub / local skills."
      },
      "ModifyConfig": {
        "label": "Modify configuration",
        "description": "Write changes back to config.toml."
      },
      "ManageUsers": {
        "label": "Manage users",
        "description": "Create / delete users and rebind identities."
      }
    }
  },
  "user_budget": {
    "title": "User budget",
    "back": "Back to users",
    "loading": "Loading…",
    "fetch_error": "Failed to load budget",
    "set_limits": "Set spend limits",
    "current_spend": "Current spend (USD)",
    "alert_breach": "alert breach",
    "enforced": "enforced",
    "deferred": "enforcement deferred",
    "save": "Save",
    "saving": "Saving…",
    "clear": "Clear cap",
    "clearing": "Clearing…",
    "discard": "Discard",
    "zero_means_unlimited": "Set any window to 0 for unlimited on that window. Threshold is the fraction of any limit at which a BudgetExceeded audit fires.",
    "help": "Per-user spend cap. Anything one user does — across every agent, every channel — counts against this cap. Set caps here when you want to give a teammate access to your LibreFang instance without them being able to drain your provider credit.\n\nHow budgets stack:\n\n  · Global budget (set in /dashboard/runtime) — kernel-wide ceiling. Hits this and every agent stops.\n  · Per-agent budget (set in agent.toml) — caps a specific agent's spend.\n  · Per-user budget (this page) — caps a specific user's combined spend.\n  · The most restrictive limit wins. If global has $5 left and the user has $50 left, the user can spend $5.\n\nWhat you see here:\n\n  · Current spend (this period), the cap, percent used, and the rolling window (daily / weekly / monthly).\n  · \"alert_breach\" badge appears when the user has crossed an alert threshold but is still under the hard cap.\n  · Per-provider breakdown: which providers contributed how much to the user's spend.\n\nThings to know:\n\n  · A user with no budget configured is unlimited (still subject to global / per-agent caps).\n  · Edits take effect on the next request the user makes — already-running LLM calls continue.\n  · Spend totals are persisted in SQLite; deleting the user does not delete history (audit trail).",
    "of_cap": "of {{cap}}",
    "over_threshold": "over threshold",
    "no_cap": "no cap on this window"
  },
  "user_policy": {
    "title": "Permission matrix",
    "back": "Back to users",
    "save": "Save",
    "saved": "Policy saved.",
    "load_error_title": "Failed to load policy",
    "load_error_body": "The daemon returned an error fetching the per-user policy slice.",
    "section_tool_policy": "Tool allow / deny",
    "tool_policy_desc": "Per-user allow + deny patterns. Layered ON TOP of agent + channel rules. Deny wins.",
    "allowed_tools": "Allowed tools",
    "denied_tools": "Denied tools",
    "glob_hint": "One pattern per line. Glob with `*` allowed.",
    "glob_hint_deny": "Always wins over allow.",
    "section_categories": "Tool categories",
    "categories_desc": "Bulk allow / deny by tool group name (defined in `KernelConfig.tool_policy.groups`).",
    "allowed_groups": "Allowed groups",
    "denied_groups": "Denied groups",
    "group_hint": "One group name per line (e.g. `web_tools`).",
    "section_memory": "Memory access",
    "memory_desc": "Namespace ACL + PII redaction toggles. Writable must be a subset of readable.",
    "readable_ns": "Readable namespaces",
    "writable_ns": "Writable namespaces",
    "ns_hint": "One namespace per line. `*` matches all.",
    "writable_hint": "Must be a subset of readable.",
    "pii_access": "PII access",
    "export_allowed": "Export allowed",
    "delete_allowed": "Delete allowed",
    "section_channels": "Per-channel tool rules",
    "channels_desc": "Override the user's tool surface per channel adapter (telegram / discord / …). Add custom adapters with the input below.",
    "custom_channel": "custom",
    "remove_channel": "Remove channel",
    "add_channel_label": "Add channel",
    "add_channel_placeholder": "wechat, matrix, …",
    "add_channel_hint": "Channel adapter name (lowercase). Must match the key the bridge emits.",
    "add_channel_err_empty": "Channel name is required.",
    "add_channel_err_duplicate": "Channel '{{key}}' already has a rule slot.",
    "help": "The full RBAC picture for one user: which tools they can call, which categories are allowed, which channel rules apply to them, and which agents they can talk to. Read-only summary — to change values, edit the user via the Users page or the kernel config.\n\nThree slices contribute to every gate decision:\n\n  · Per-user tool_policy / tool_categories — overrides on this page.\n  · Per-agent ToolPolicy — set in agent.toml.\n  · Per-channel rules — set in [channels.<name>] config.\n\nHow to use:\n\n  1. Pick the user (header). The page is scoped to that user across all sections.\n  2. Each slice shows: configured rules + \"not configured\" markers (which mean \"fall through to the next layer\").\n  3. Use the Permission Simulator (/dashboard/permission-simulator) to see what the gate decides for a specific tool call once all three slices intersect.\n\nPermission matrix (this page) vs. Permission simulator:\n\n  · Matrix — raw configured slices, no decision logic.\n  · Simulator — runs the actual intersection for a specific (user, agent, tool, channel) tuple and tells you the verdict.\n\nThings to know:\n\n  · \"Not configured\" never means \"denied\". It means \"defer to other layers\". A user with no tool_policy is still bound by per-agent and per-channel rules.\n  · Channel rules are evaluated only when the request comes via that channel; web-dashboard and CLI calls bypass channel rules.\n  · This page is read-only. Edits are at /dashboard/users → click the user → edit modal."
  },
  "tool_policy": {
    "allowed_tools": "Allowed tools",
    "denied_tools": "Denied tools"
  },
  "tool_categories": {
    "allowed_groups": "Allowed groups",
    "denied_groups": "Denied groups"
  },
  "memory_access": {
    "readable_namespaces": "Readable namespaces",
    "writable_namespaces": "Writable namespaces"
  },
  "simulator": {
    "title": "Permission simulator",
    "subtitle": "Pick a user and see every RBAC input contributing to their permissions.",
    "badge": "Live",
    "user_label": "User",
    "choose_user": "Select a user…",
    "empty_title": "No users to simulate",
    "empty_desc": "Add a user from the Users page first.",
    "not_found_title": "User not found",
    "not_found_desc": "The selected user is not registered with the AuthManager. They may have been removed from config.toml since the user list cached.",
    "error_title": "Could not load effective permissions",
    "role_matrix_caption": "Role-level coarse permissions",
    "requires": "Requires",
    "help": "The permission simulator picks a user and shows every RBAC input that contributes to their effective permissions — role, tool policy, allowed / denied tool lists, allowed / denied groups, channel rules and bindings, memory namespaces, budget caps, PII access, delete / export permissions. It's a debug surface for \"why does (or doesn't) this user have access to X\".\n\nHow to use this page:\n\n1. Pick a user. Use the chooser; the page populates with their slices.\n\n2. Read each section. Every section shows the RAW configured slice for that user — role matrix, tool policy, channel bindings, memory permissions, budget, etc. \"Not configured\" means that layer is silent for this user.\n\n3. Compare with reality. The runtime intersects these slices at call time; this page does NOT show the per-call gate decision, only the inputs.\n\nWhen to use it (vs. running the actual agent):\n\n  · Simulator — fast static view of every input, no LLM call needed.\n  · Actual agent call — the only ground truth for what runs / doesn't.\n\nTypical scenarios:\n\n  · \"Why can't user @bob delete memories?\" — section shows delete_off.\n  · \"Did the new tool policy actually land for @alice?\" — see allowed / denied lists.\n  · Auditing channel rule coverage before granting a new external user access.\n\nThings to know:\n\n  · Sections show RAW slices, not the gate decision. The runtime gate intersects per-agent ToolPolicy + per-user tool_policy / tool_categories + per-channel rules; \"Not configured\" defers to other layers.\n  · The simulator reads current config — changes you make on Users / Policy pages take effect immediately on refresh.",
    "tool_policy_title": "Tool policy (per-user)",
    "tool_policy_unset": "Defers to per-agent ToolPolicy and channel rules.",
    "allowed_tools": "Allowed",
    "denied_tools": "Denied",
    "no_allow_list": "No allow-list set",
    "no_deny_list": "No deny-list set",
    "tool_categories_title": "Tool categories (bulk by ToolGroup)",
    "tool_categories_unset": "No category-level overrides for this user.",
    "allowed_groups": "Allowed groups",
    "denied_groups": "Denied groups",
    "memory_title": "Memory access",
    "memory_unset": "Falls back to the role-default ACL (Owner/Admin = full, User = proactive + kv:*, Viewer = proactive read-only).",
    "readable_namespaces": "Readable namespaces",
    "writable_namespaces": "Writable namespaces",
    "no_namespaces": "No namespaces",
    "pii_access_on": "PII access ON",
    "pii_access_off": "PII redacted",
    "export_on": "Export allowed",
    "export_off": "No export",
    "delete_on": "Delete allowed",
    "delete_off": "No delete",
    "budget_title": "Per-user budget caps",
    "budget_unset": "No per-user cap. Bounded by global / per-agent / per-provider budgets only.",
    "budget_hourly": "Hourly",
    "budget_daily": "Daily",
    "budget_monthly": "Monthly",
    "alert_threshold_label": "Alert threshold",
    "channel_bindings_title": "Channel bindings",
    "bindings_unset": "No platform IDs bound. Inbound from any channel will be unrecognised.",
    "channel_rules_title": "Per-channel tool overrides",
    "channel_rules_unset": "No per-channel overrides. The global ApprovalPolicy.channel_rules still applies."
  },
  "offline_banner": {
    "label": "Daemon unreachable",
    "retry": "Retry"
  },
  "connect_wizard": {
    "title": "Connect to Daemon",
    "subtitle": "Enter your daemon URL and API key, or scan a pairing QR code.",
    "tab_manual": "Manual",
    "tab_qr": "Scan QR",
    "field_url": "Daemon URL",
    "field_api_key": "API Key",
    "field_device_name": "Device name",
    "device_name_placeholder": "My iPhone",
    "device_name_help": "Shown on the desktop so you can revoke this device later.",
    "qr_card_title": "Open the desktop dashboard",
    "qr_card_body": "Go to <strong>Settings → Mobile Pairing</strong> and tap <strong>Scan QR</strong> below.",
    "btn_connect": "Connect",
    "btn_connecting": "Connecting…",
    "btn_scan": "Scan QR Code",
    "btn_scanning": "Scanning…",
    "btn_pairing": "Pairing…",
    "done_title": "Connected!",
    "done_subtitle": "Opening dashboard…",
    "error_title": "Connection failed",
    "error_url_scheme": "URL must start with http:// or https://",
    "error_default_connect": "Connection failed",
    "error_default_pairing": "Pairing failed",
    "btn_try_again": "Try again",
    "device_name_default": "LibreFang Mobile"
  },
  "mobile_pairing": {
    "title": "Mobile Pairing",
    "subtitle": "Open the LibreFang mobile app and tap <strong>Scan QR</strong> to connect to this daemon.",
    "expired_message": "QR code expired — refresh to get a new one.",
    "refresh": "Refresh",
    "expired_label": "Expired",
    "paired_devices_heading": "Paired Devices",
    "paired_at": "{{platform}} · paired {{date}}",
    "remove_title": "Remove device",
    "remove_failed": "Failed to remove device: {{reason}}",
    "remove_unknown_error": "unknown error",
    "error_disabled_title": "Device pairing is disabled",
    "error_disabled_body": "Enable pairing in <link>Config → Security</link> (<code>pairing.enabled = true</code>).",
    "error_generic_title": "Failed to generate pairing code",
    "qr_aria_label": "QR code for pairing with a mobile device",
    "btn_try_again": "Try again"
  },
  "shortcuts_help": {
    "title": "Keyboard shortcuts",
    "general_heading": "General",
    "nav_heading_prefix": "Navigate (press",
    "nav_heading_suffix": "then…)",
    "general": {
      "cmd_k": "Open command palette",
      "focus_search": "Focus search on current page",
      "create_new": "Create new (agent / workflow / plugin, page-aware)",
      "show_help": "Show this cheat sheet",
      "close_dialog": "Close dialog / modal"
    },
    "nav": {
      "overview": "Overview",
      "chat": "Chat",
      "agents": "Agents",
      "hands": "Hands",
      "skills": "Skills",
      "workflows": "Workflows",
      "models": "Models",
      "providers": "Providers",
      "channels": "Channels (Network)",
      "goals": "Goals",
      "logs": "Logs",
      "runtime": "Runtime",
      "memory": "Memory",
      "analytics": "Analytics",
      "settings": "Settings",
      "plugins": "Plugins",
      "scheduler": "Scheduler",
      "approvals": "Approvals (reView)",
      "sessions": "Sessions"
    }
  },
  "prompts_experiments": {
    "subtitle": "Prompts & Experiments",
    "tab_versions": "Versions",
    "tab_experiments": "Experiments",
    "new_version": "New Version",
    "no_versions": "No prompt versions yet",
    "active": "Active",
    "activate": "Activate",
    "created_label": "Created:",
    "create_version_title": "Create Prompt Version",
    "system_prompt_label": "System Prompt",
    "system_prompt_placeholder": "You are a helpful AI assistant...",
    "description_optional": "Description (optional)",
    "description_placeholder": "What's different in this version?",
    "creating": "Creating...",
    "create": "Create",
    "cancel": "Cancel",
    "new_experiment": "New Experiment",
    "no_experiments": "No experiments yet",
    "start": "Start",
    "pause": "Pause",
    "complete": "Complete",
    "metrics": "Metrics",
    "experiment_metrics": "Experiment Metrics",
    "requests": "Requests",
    "avg_latency": "Avg Latency",
    "avg_cost": "Avg Cost",
    "close_metrics": "Close Metrics",
    "create_experiment_title": "Create Experiment",
    "experiment_name_label": "Experiment Name",
    "experiment_name_placeholder": "My A/B Test",
    "select_versions_label": "Select Prompt Versions (min 2)",
    "min_versions_warning": "Create at least 2 prompt versions first.",
    "control": "Control",
    "variant_label": "Variant {{letter}}",
    "create_with_count": "Create ({{count}} variants)"
  }
}
