{ "title": "Settings", "subtitle": "Manage appearance, AI tools, notifications and data", "exportData": "Export Data", "acrossSessions": "Across all tracked sessions", "basedOnUsage": "Based on per-model token usage", "sagi": { "title": "Sagi companion", "description": "A floating mascot that reacts to your live sessions.", "enable": "Show Sagi", "enableDesc": "Display the corner companion across the dashboard (⌘B to open)" }, "pricing": { "title": "Model Pricing", "description": "Rates per million tokens (USD). Use % as wildcard in patterns. Some models have a time-limited introductory rate (shown in violet); usage on or before its cutoff date is billed at that rate, and usage after it at the standard rate.", "introNote": "Intro ${{input}}/${{output}} through {{until}}", "introRatesTitle": "Introductory rates", "introRatesHint": "Leave the date empty for no promo", "introUntil": "Through (date)", "introUntilInvalid": "Introductory cutoff must be a YYYY-MM-DD date", "resetConfirm": "Confirm Reset", "resetDefaults": "Reset Defaults", "resetResult": "Reset to {{count}} default rules", "addModel": "Add Model", "pattern": "Pattern", "validationRequired": "Pattern and display name are required", "lastUpdated": "Last updated: ", "tooltip": { "title": "How model pricing works", "howItWorks": "How it works", "howItWorksBody": "When a session reports usage, the dashboard finds the first pricing rule whose pattern matches the model id and multiplies (input tokens / 1M) and (output tokens / 1M) by the rates below to compute cost. Rules are evaluated top-to-bottom - the first match wins.", "patternsTitle": "Pattern syntax", "patternsBody": "Patterns are SQL-style globs. % is a wildcard that matches any characters. For example: claude-opus-4-7% matches every model id that starts with claude-opus-4-7 (e.g. claude-opus-4-7, claude-opus-4-7-20260101). claude-%-haiku matches any haiku variant. An exact id like claude-sonnet-4-6 only matches itself.", "apiPricing": "Reference only - API rates", "apiPricingBody": "These are pay-as-you-go API rates. If you use Claude Code on a subscription plan (Pro, Max, Team, or Enterprise), your actual cost is a flat monthly fee, not per-token - so these figures will usually be higher than what you really pay. Treat the costs here as a usage estimate for reference, not a bill.", "synced": "Prices are filled in automatically", "syncedBody": "Every current Claude, OpenAI and Gemini model is priced from LiteLLM's public price list, checked once a day, as is any other model the moment a session uses it. Rows marked Auto follow that list when a rate changes; a row you edit becomes yours and is never touched again, and a row you delete stays deleted. Already-stored sessions keep the price that was applied at ingest time.", "apiPricingOtherBody": "These are pay-as-you-go API rates. If you use this CLI on a subscription plan, your actual cost is a flat fee, not per-token - so these figures will usually be higher than what you really pay. Treat them as a usage estimate, not a bill." }, "cacheWrite5m": "Cache Write (5m)", "cacheWrite1h": "Cache Write (1h)", "fastInput": "Fast Input", "fastOutput": "Fast Output", "showAll": "Show all models ({{count}} more)", "empty": { "claude": "No Claude model prices. Reset Defaults restores them.", "openai": "No OpenAI model prices yet. They are added automatically from LiteLLM's price list once a Codex session uses a model, or add one yourself.", "google": "No Gemini model prices yet. They are added automatically from LiteLLM's price list once an Antigravity session uses a model, or add one yourself." }, "placeholders": { "claude": { "pattern": "claude-opus-4%", "name": "Claude Opus 4" }, "openai": { "pattern": "gpt-5%", "name": "GPT 5" }, "google": { "pattern": "gemini-3.8-flash%", "name": "Gemini 3.8 Flash" } }, "autoBadge": "Auto", "autoBadgeTitle": "Kept at the published rate automatically (LiteLLM's price list, checked daily). Edit it to keep your own rate." }, "claudeHome": { "title": "CLAUDE_HOME", "description": "Root directory for Claude Code session data. Changing this updates the scan path for transcripts and imports immediately.", "placeholder": "/path/to/claude-home", "routersMissing": "Saved. These lanes name an AI Router profile the new home does not have, and start on Native until it is added there or they are re-pointed: {{lanes}}" }, "hooks": { "title": "Hook Configuration", "description": "Claude Code hooks forward events to the dashboard in real time.", "allInstalled": "All hooks installed", "incomplete": "Hooks incomplete", "reinstall": "Reinstall Hooks", "success": "Hooks installed successfully", "failed": "Hook installation failed" }, "lanesSection": { "title": "Lanes", "description": "Machine-wide lane housekeeping.", "runHousekeeping": "Run housekeeping", "dryRun": "Dry run", "gcResult": "Reaped {{reaped}} process(es), capped {{capped}} log(s)" }, "notifications": { "awaitingInput": "Claude needs confirmation", "blocked": "Permission blocked", "description": "Browser notifications for important events. Requires permission.", "disabledInfo": "Notifications are disabled - enable to get alerts for session events", "enable": "Enable Browser Notifications", "granted": "Permission granted", "newSession": "New session starts", "notifyWhen": "Notify me when...", "required": "Permission required", "sendTest": "Send Test Notification", "sessionComplete": "Session completes", "sessionError": "Session errors", "subagentSpawned": "Subagent spawned", "testBlocked": "The browser has not granted notification permission.", "testBody": "Notifications are working!", "testFailed": "Nothing could be shown.", "testLocal": "Your browser has no push subscription, so this was shown locally. Web Push needs a secure origin (localhost or HTTPS) and a registered service worker.", "testSent": "Sent via push — check your notification centre.", "testTitle": "Agent Monitor", "title": "Notifications", "turnComplete": "Claude finishes a turn" }, "import": { "title": "Import History", "description": "Bring existing Claude Code sessions into the dashboard. Token counts, per-model cost, compactions, subagents, tool uses, and turn durations are reconstructed from the original JSONL transcripts - identical to how live sessions are captured.", "accuracyNote": "Re-running is safe. Sessions are deduplicated by session ID, and compaction baselines ensure token totals never double-count.", "supportedFiles": "Supported inputs: .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz", "instructions": "How to gather your history", "stepLocate": "1. Locate your Claude Code history", "stepLocateBody": "Every Claude Code session is stored as a JSONL transcript under the projects folder. Each subfolder is named after the working directory where the session started (slashes replaced with dashes).", "stepArchive": "2. Bundle it for transfer (optional)", "stepArchiveBody": "To move history from another machine, archive the whole folder first, then copy it over (AirDrop, scp, USB, cloud storage):", "stepChoose": "3. Pick an import mode below", "stepChooseBody": "Rescan the default location, point at any folder you've extracted history into, or upload files/archives directly.", "stepVerify": "4. Verify tokens and cost", "stepVerifyBody": "After import, open Analytics → Cost to confirm the breakdown. Re-importing the same session is always safe.", "defaultLocation": "Default location on this machine", "locationFound": "Folder found", "locationMissing": "Folder not found", "projectsLabel": "projects", "jsonlLabel": "JSONL files", "modeRescan": "Rescan default folder", "modeRescanDesc": "Re-read ~/.claude/projects and import anything new.", "modeFolder": "Scan a folder", "modeFolderDesc": "Scan any directory on this machine for JSONL transcripts (walks subfolders).", "modeUpload": "Upload files", "modeUploadDesc": "Drop JSONL files or an archive (.zip / .tar.gz) directly into the browser.", "modeBackup": "Restore backup", "modeBackupDesc": "Import a dashboard export (.json) from Export data — merge another machine's history in.", "backupHint": "Drop an export .json here or click to select", "backupSub": "The file produced by the Export data button (top of Settings)", "runRestore": "Restore", "backupResult": { "title": "Restore complete", "sessionsImported": "Sessions added: {{count}}", "sessionsSkipped": "Already present: {{count}}", "events": "Events: {{count}}", "pricing": "Pricing rules: {{count}}", "detail": "{{agents}} agents · {{workflows}} workflows · {{runs}} runs · {{rules}} alert rules" }, "folderPlaceholder": "/absolute/path/to/claude-history", "folderHelper": "Absolute path. Tilde (~) is expanded. Subfolders are scanned recursively.", "runRescan": "Rescan Now", "runScan": "Scan Folder", "runUpload": "Upload & Import", "dropzoneHint": "Drag files here or click to select", "dropzoneSub": "Accepts .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz", "filesSelected": "{{count}} file(s) selected", "clearSelection": "Clear", "copy": "Copy", "copied": "Copied", "progress": { "scan": "Scanning directory...", "extract": "Extracting archives ({{processed}}/{{total}})...", "parse": "Parsing transcripts ({{processed}}/{{total}})...", "complete": "Import complete", "error": "Import failed" }, "result": { "imported": "Imported: {{count}}", "backfilled": "Enriched existing: {{count}}", "skipped": "Already up to date: {{count}}", "errors": "Errors: {{count}}", "filesScanned": "Files scanned: {{count}}", "title": "Last import result" }, "errors": { "noFiles": "No files selected", "noJsonl": "No .jsonl files were found in the uploaded content", "pathRequired": "Path is required", "pathInvalid": "Path must be absolute", "pathNotFound": "Path does not exist", "pathNotDir": "Path is not a directory", "generic": "Import failed: {{message}}" } }, "data": { "title": "Data Management", "description": "Database info, import/export, and cleanup.", "dbOverview": "Database Overview", "dbSize": "DB Size", "loadingDb": "Loading database info...", "sessionCleanup": "Session Cleanup", "cleanupDesc": "Abandon stale sessions and purge old data", "abandonAfter": "Abandon stale active sessions older than", "purgeAfter": "Purge completed/errored sessions older than", "confirmCleanup": "Confirm Cleanup", "runCleanup": "Run Cleanup", "nothingToClean": "Nothing to clean up", "abandonedResult": " sessions abandoned", "purgedResult": " sessions purged ({{events}} events, {{agents}} agents)" }, "danger": { "title": "Danger Zone", "description": "Irreversible actions that delete data permanently", "warning": "This will delete all sessions, agents, events, and token data. Are you sure?", "yesClearAll": "Yes, Clear All", "clearAllData": "Clear All Data", "clearedResult": "Cleared {{count}} rows" }, "about": { "title": "About", "description": "Server runtime information.", "release": "Release", "uiBuild": "UI build v{{version}} (rebuild client to match)", "uptime": "Uptime", "nodejs": "Node.js", "platform": "Platform", "wsClients": "WS Clients", "loadingInfo": "Loading server info..." }, "tables": { "sessions": "sessions", "agents": "agents", "events": "events", "sessionsWithCost": "sessions with cost", "pricingRules": "pricing rules" }, "messages": { "failedLoad": "Failed to load", "failedSave": "Failed to save", "failedDelete": "Failed to delete", "unknownError": "Unknown", "actionFailed": "Error: {{message}}" }, "webhooks": { "title": "Webhook Notifications", "description": "Forward fired alerts to Slack, Discord, Microsoft Teams, or any HTTP endpoint. Delivery is automatic, retried on failure, and never blocks monitoring.", "count_one": "{{count}} target", "count_other": "{{count}} targets", "add": "Add Webhook", "loading": "Loading webhooks…", "empty": "No webhooks configured. Add one to forward alerts to Slack, Discord, Teams, or a custom endpoint.", "scopedTo_one": "{{count}} rule", "scopedTo_other": "{{count}} rules", "enabled": "Enabled", "test": "Test", "edit": "Edit", "delete": "Delete", "confirmDelete": "Confirm", "testOk": "Delivered (HTTP {{status}})", "testFail": "Failed: {{error}}", "addTitle": "New Webhook", "editTitle": "Edit Webhook", "fieldName": "Name", "fieldNamePlaceholder": "e.g. Team Slack #alerts", "fieldType": "Type", "type": { "slack": "Slack", "discord": "Discord", "teams": "Microsoft Teams", "generic": "Generic (custom JSON)" }, "fieldUrl": "Webhook URL", "urlKeepHint": "leave blank to keep current", "urlKeepPlaceholder": "•••••••• (unchanged)", "urlPlaceholder": { "slack": "https://hooks.slack.com/services/…", "discord": "https://discord.com/api/webhooks/…", "teams": "https://outlook.office.com/webhook/…", "generic": "https://example.com/webhook" }, "fieldSecret": "Signing secret (optional)", "secretPlaceholder": "HMAC-SHA256 secret", "secretKeepPlaceholder": "•••••••• (leave blank to keep)", "secretHint": "When set, requests are signed with an X-Webhook-Signature header.", "fieldHeaders": "Custom headers (optional)", "replaceHeaders": "Replace headers", "headerKey": "Header", "headerValue": "Value", "addHeader": "Add header", "scopeAll": "Receive alerts from all rules", "enabledOnSave": "Enabled", "save": "Save", "create": "Create", "cancel": "Cancel", "urlOptional": "optional override", "urlAuto": "URL is set automatically from the credentials below.", "deleteTitle": "Delete webhook?", "deleteMessage": "Delete \"{{name}}\"? Fired alerts will stop being delivered to this target. This cannot be undone.", "guideToggle": "How to set up {{provider}}", "guideDocs": "Official {{provider}} docs", "guideStaleNote": "Provider setup screens change often, so these steps may be out of date - always confirm against the official docs." }, "alertsHub": { "title": "Alerts", "description": "Define alert rules, route them to webhook channels, and review what has fired - all in one place.", "tabRules": "Rules", "tabChannels": "Channels", "tabActivity": "Activity", "rulesHint": "Conditions that trigger an alert. Evaluated server-side against the live event stream.", "rulesEmptyHint": "Add a rule to start alerting on errors, inactivity, stuck agents, or token thresholds." }, "jumpTo": "Jump to", "webhookGuides": { "slack": { "steps": [ "Create or open a Slack app at api.slack.com/apps.", "Turn on 'Incoming Webhooks', then click 'Add New Webhook to Workspace'.", "Choose the channel to post to and authorize.", "Copy the generated URL (https://hooks.slack.com/services/…) and paste it above." ] }, "discord": { "steps": [ "Open your server → Server Settings → Integrations → Webhooks.", "Click 'New Webhook', pick a channel, optionally rename it.", "Click 'Copy Webhook URL' and paste it above." ] }, "teams": { "steps": [ "In the target Teams channel, click ⋯ → 'Workflows'.", "Pick the template 'Post to a channel when a webhook request is received'.", "Finish the flow and copy the generated HTTP POST URL.", "Paste it above. (Classic Office 365 connectors were retired in 2025 - use Workflows.)" ] }, "google_chat": { "steps": [ "Open the Google Chat space → space title → 'Apps & integrations'.", "Click 'Webhooks' → 'Add webhook' and give it a name.", "Copy the webhook URL and paste it above." ] }, "mattermost": { "steps": [ "Main Menu → Integrations → Incoming Webhooks (an admin must enable webhooks first).", "Click 'Add Incoming Webhook' and choose a channel.", "Save, then copy the webhook URL and paste it above." ] }, "rocketchat": { "steps": [ "Administration → Integrations → New → Incoming.", "Enable it, pick a channel, and save.", "Copy the 'Webhook URL' and paste it above." ] }, "telegram": { "steps": [ "Message @BotFather, run /newbot, and copy the bot token.", "Add the bot to your group/channel (or just DM it).", "Find the chat ID: send a message, open https://api.telegram.org/bot/getUpdates, read result[].message.chat.id.", "Enter the Bot token and Chat ID above - no URL needed." ] }, "pagerduty": { "steps": [ "Open the target Service → Integrations → 'Add integration'.", "Choose 'Events API v2'.", "Copy the Integration Key (the routing key).", "Enter it as the Routing key above - the Events API URL is prefilled." ] }, "opsgenie": { "steps": [ "Settings → Integrations → add an 'API' integration.", "Copy the generated API key.", "Note your account region (US or EU).", "Enter the API key and region above - the alerts URL is derived from the region." ] }, "splunk_oncall": { "steps": [ "Integrations → REST Endpoint, and enable it.", "Copy the REST URL - it already contains your API key.", "Replace the trailing '$routing_key' with one of your routing keys.", "Paste the full URL above." ] }, "zapier": { "steps": [ "Create a Zap with the trigger 'Webhooks by Zapier' → 'Catch Hook'.", "Copy the custom webhook URL it gives you.", "Paste it above. The alert arrives as JSON: { event, alert }." ] }, "make": { "steps": [ "Add a 'Webhooks' → 'Custom webhook' module as the first step of a scenario.", "Click 'Add', create the hook, and copy its URL.", "Paste it above, then run once so Make learns the payload shape." ] }, "n8n": { "steps": [ "Add a 'Webhook' node to your workflow; set the method to POST.", "Copy the Production URL.", "Activate the workflow and paste the URL above (http is allowed for self-hosted)." ] }, "pipedream": { "steps": [ "Create a workflow with an 'HTTP / Webhook' trigger.", "Copy the unique endpoint URL.", "Paste it above; inspect deliveries in the Pipedream event inspector." ] }, "generic": { "steps": [ "Point this at any endpoint that accepts a JSON POST (https, or http for local testing).", "Body shape: { event: 'alert.triggered', source, sent_at, alert: { … } }.", "Optional: set a signing secret (HMAC-SHA256 over the body → X-Webhook-Signature header) and custom headers.", "Tip: use a free inspector like webhook.site to see the exact payload." ] } }, "remoteSources": { "title": "Remote Data Sources", "description": "Collect Claude Code usage from other machines over SSH - e.g. a dev box or cloud VM you drive over SSH while running this dashboard locally. Authentication uses your own SSH setup (~/.ssh/config, keys, agent); no passwords are stored here.", "scopeTitle": "Data scope", "scopeDesc": "Choose which machines' data the whole dashboard shows. Changes apply immediately across every page — sessions, analytics, and cost.", "scopeAll": "All sources", "scopeAllDesc": "This machine plus every configured remote source, combined.", "scopeLocal": "This machine only", "scopeLocalDesc": "Only sessions collected locally — hides all remote-source data.", "scopeSelected": "Selected sources", "scopeSelectedDesc": "Pick exactly which machines to include, below.", "scopeSelectedCount": "{{n}} of {{total}} selected", "scopePickMachines": "Machines to include", "thisMachine": "This machine", "listTitle": "Configured sources", "add": "Add source", "addTitle": "Add a remote source", "editTitle": "Edit source", "fieldLabel": "Label", "fieldHost": "SSH host", "fieldPort": "Port (optional)", "fieldIdentity": "Identity file (optional)", "fieldRemoteHome": "Remote Claude home (optional)", "fieldRemoteHomeHint": "Linux/macOS: default ~/.claude (or an absolute path like /home/you/.claude). Windows SSH + Claude in WSL: leave blank (auto-detect) or use wsl:~/.claude. Native Windows: C:/Users/you/.claude.", "fieldEnabled": "Sync automatically in the background", "empty": "No remote sources yet.", "emptyHint": "Add a machine you reach over SSH to pull its Claude Code usage in.", "paused": "Auto-sync off", "sessionCount": "{{n}} sessions", "sessionCountLinked": "{{n}} linked", "sessionCountHint": "Sessions linked to this source (not every session visible when data scope is All)", "lastSync": "Last sync: {{when}}", "neverSynced": "Never synced", "imported": "{{n}} imported", "syncNew": "{{n}} new", "syncOnRemote": "{{n}} on remote", "test": "Test", "syncNow": "Sync", "syncAll": "Sync all", "enable": "Enable", "disable": "Disable", "confirmDelete": "Remove this source?", "purgeData": "Also delete the sessions imported from this source (cannot be undone)", "deleteAndPurge": "Remove + delete data", "removeKeep": "Remove (keep data)", "remoteSourceBadgeTitle": "Collected from a remote machine" }, "cursorPathsNote": "Informational: Cursor sessions count here too — Cursor happens to use the same ~/.claude paths as Claude Code (locally and on synced remotes).", "tools": { "label": "Tools", "dashboard": "Dashboard", "claudeCode": "Claude Code", "codex": "Codex", "antigravity": "Antigravity", "aiRouter": "AI Router", "gitCredentials": "Git credentials" }, "aiRouter": { "title": "AI Router", "description": "Endpoints that stand in front of Claude Code and Codex — 9Router, OpenRouter, a self-hosted gateway. Save one here, then pick it when you create a lane.", "add": "Add profile", "edit": "Edit", "remove": "Remove", "empty": "No router profile saved yet. Native runs against the vendor's own API.", "builtinHint": "Built in — this is the vendor's own API, and it cannot be edited or removed.", "colLabel": "Profile", "colBaseUrl": "Endpoint", "colModel": "Model", "colKey": "API key", "keySet": "Saved", "keyMissing": "None", "fieldLabel": "Name", "fieldLabelHint": "What you will see in the lane form. Free text.", "fieldBaseUrl": "Base URL", "fieldBaseUrlHint": "The router's OpenAI/Anthropic-compatible endpoint, e.g. http://localhost:20128/v1", "fieldApiKey": "API key", "fieldApiKeyHint": "Stored on this machine at 0600 and never sent back to the browser.", "fieldApiKeyKeep": "Leave blank to keep the saved key.", "fieldModel": "Model", "fieldModelHint": "Used for every tier unless you override one below. Many routers accept one symbolic name.", "perTier": "Per-tier overrides", "perTierHint": "Leave a field blank to use the model above.", "tier": { "opus": "Opus", "sonnet": "Sonnet", "haiku": "Haiku", "smallFast": "Small / fast", "subagent": "Subagent" }, "save": "Save", "cancel": "Cancel", "removeConfirm": "Remove the profile \"{{label}}\"? Every lane using it is reset to the vendor's own API right away — on disk and in the dashboard.", "loading": "Loading profiles…", "lanesFailed": "Saved, but {{count}} lane could not be updated and still carries the old endpoint: {{lanes}}", "test": "Test", "testing": "Testing…", "testOk": "The endpoint answered — {{model}} is reachable with this key.", "testFailed": "No answer ({{status}}): {{message}}" }, "aiTools": { "title": "AI Tools", "description": "AI coding CLIs AgentHub can run in a lane. Detected on this machine's PATH; a disabled tool is hidden from Add lane.", "installed": "Installed ({{count}} detected)", "available": "Available to install ({{count}})", "refresh": "Refresh", "noneInstalled": "No AI tool found on PATH. Install one, then press Refresh.", "default": "Default", "setDefault": "Set default", "enabled": "Enabled", "disabled": "Disabled", "enabledOf": "{{tool}} enabled", "homepage": "Homepage", "homepageOf": "{{tool}} homepage", "install": "Install", "update": "Update", "updateAll": "Update all ({{count}})", "runScript": "Download {{url}} and run it with bash", "confirmInstall": "Install {{tool}}?", "confirmUpdate": "Update {{tool}}?", "confirmUpdateAll": "Update AI tools?", "confirmBody": "AgentHub will run on this machine:", "run": "Run", "cancel": "Cancel", "jobRunning": "Running…", "jobOk": "Done", "jobFailed": "Failed (exit {{code}})", "showLog": "Show log", "hideLog": "Hide log" }, "appearance": { "title": "Appearance", "description": "Colour mode and theme. Saved in this browser only.", "mode": "Mode", "modes": { "dark": "Dark", "light": "Light", "system": "System" }, "darkThemes": "Dark themes", "lightThemes": "Light themes", "active": "· in use now", "default": "Default" }, "gitCreds": { "title": "Git credentials", "description": "Logins AgentHub gives git for a dashboard fetch, pull or push — one per host, shared by everyone using this AgentHub. A token is never shown again after it is saved.", "add": "Add login", "replace": "Replace token", "remove": "Delete", "removeConfirm": "Delete this git login? Dashboard fetch/pull/push to that host will ask for a login again.", "save": "Save", "cancel": "Cancel", "fieldHost": "Server URL", "fieldUser": "Username", "fieldToken": "Password or access token", "colHost": "Host", "colUser": "Username", "colSaved": "Saved", "empty": "No git login saved. The git bar asks for one the first time a host needs it.", "badUrl": "Enter the server as a URL, e.g. https://git.example.com" }, "homeDir": { "save": "Save", "saving": "Saving...", "current": "Current:", "saveFailed": "Failed to save the directory", "envOwned": "This variable is set by the environment the dashboard started in, or by the checkout's .env — either wins at every start: a value saved here lasts until the next restart." }, "codexHome": { "title": "CODEX_HOME", "description": "Root directory for Codex config and session journals. The dashboard reads it, writes AI Router layers into it, and starts every codex lane with it.", "restartNote": "A codex lane already running keeps the home it started with, and shows as idle, until it is restarted.", "placeholder": "/path/to/codex-home", "routersFailed": "Saved, but the AI Router layer could not be re-written for: {{lanes}}" }, "codexHooks": { "title": "Codex hooks", "description": "Let Codex report to AgentHub as it works: each tool call in the session's timeline, \"Codex needs your permission\" on the lane card and as a notification, and running/idle the moment a turn starts or ends. Tokens and cost come from Codex's journals either way.", "notInstalled": "Not installed", "untrusted": "Installed — waiting for your trust in Codex", "trusted": "Installed and trusted", "trustNote": "Codex runs a hook only after you trust it. The next time Codex starts it asks you to review new hooks: choose Trust all and continue (or run /hooks). Until then Codex skips them.", "install": "Install", "reinstall": "Reinstall", "refresh": "Refresh", "remove": "Remove", "eventTrusted": "Trusted in Codex", "eventUntrusted": "Not trusted in Codex yet", "eventMissing": "Not installed", "unsupported": "Codex hooks from AgentHub need a POSIX shell, so they are not available on Windows.", "unreadable": "AgentHub cannot read {{path}}: {{error}}", "failed": "Could not change Codex hooks: {{message}}" }, "antigravityHooks": { "title": "Antigravity hooks", "description": "Let Antigravity's CLI (agy) report to AgentHub as it works: each tool call in the session's timeline, and running/idle the moment a run starts or ends. Tokens and cost come from agy's conversation files either way.", "notInstalled": "Not installed", "installed": "Installed", "disabled": "Installed but switched off in hooks.json", "note": "agy loads hooks at its next start and asks for no trust. The file is global, so the Antigravity IDE runs the hook too; AgentHub ignores what the IDE sends. agy has no hook for a permission prompt, so an Antigravity lane cannot show \"needs your permission\".", "install": "Install", "reinstall": "Reinstall", "refresh": "Refresh", "remove": "Remove", "eventInstalled": "Installed", "eventMissing": "Not installed", "unsupported": "Antigravity hooks from AgentHub need a POSIX shell, so they are not available on Windows.", "unreadable": "AgentHub cannot read {{path}}: {{error}}", "failed": "Could not change Antigravity hooks: {{message}}" }, "toolTab": { "update": "Update…", "usage_one": "{{count}} session · ${{cost}}", "usage_other": "{{count}} sessions · ${{cost}}", "lanes": "Lanes:", "defaultModel": "Default model", "defaultModelHint": "The model a new run in this tool's lanes starts on. The run form can still pick another one.", "saveDefaultModel": "Save default model", "config": "Config files", "configHint": "This tool's own settings files. A save is checked for valid syntax, the old text is backed up in AgentHub's data folder, and nothing is saved if the file changed since you opened it.", "missing": "This file does not exist yet", "save": "Save", "close": "Close", "saved": "Saved. Backup: {{backup}}" } }