@epoch-agent/infra 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -249,6 +249,10 @@ web:
249
249
  mkdir_parent_not_absolute: 'the location to create in must be an absolute path: {parent}'
250
250
  mkdir_bad_name: 'the directory name must be a single segment with no path separators, and cannot be . or ..: {name}'
251
251
  mkdir_failed: 'could not create that directory: {path}'
252
+ pick_prompt: Choose a workspace directory
253
+ pick_unavailable: 'this machine cannot open a system directory dialog: it is only enabled when the server and the browser are on the same machine (loopback bind, not started over ssh, macOS or Windows) — use the built-in browser instead'
254
+ pick_busy: a directory dialog is already open — go answer it (this window may be covering it)
255
+ pick_failed: 'the system directory dialog could not be opened: {detail}'
252
256
  plan_mode_unavailable: this process has no plan mode (the permission layer did not start)
253
257
  plan_mode_bad_action: action must be one of {actions}
254
258
  permission_unavailable: this process has no permission layer, so the level cannot be changed (what you see is the value from the config file)
@@ -260,7 +264,7 @@ web:
260
264
  rewind_bad_overwrite: overwrite must be a list of file paths (the ones the user confirmed one by one); omit the field entirely if there is nothing to overwrite
261
265
  rewind_no_checkpoint: no checkpoint for turn {turn}
262
266
  settings_write_bad_request: the body needs key (the dotted path of the setting), layer (one of {layers}) and value (string / number / boolean)
263
- settings_write_unknown_key: that key cannot be edited here. This path writes model and maxTurns onlyevery other setting has just the built-in and user layers, and putting it in a settings file does nothing
267
+ settings_write_unknown_key: 'that key cannot be written this way: either it is not on the writable list at all (the fallback chain, for one it is an ordered chain, not a scalar), or the key only writes to the user layer while the request asked for project-local. The project layers accept permissions / model / maxTurns only; anything else lands as an "unknown setting" in the startup diagnostics'
264
268
  settings_write_bad_value: that value is outside this setting's domain (maxTurns must be a positive integer, for one), so nothing was written
265
269
  settings_write_unwritable: this layer does not recognise how {path} is written (or the file is already broken), so it was left alone — please edit that file yourself
266
270
  settings_write_io: 'writing {path} failed: possibly no write permission, or the directory could not be created'
@@ -268,6 +272,8 @@ web:
268
272
  mcp_unknown_server: This process has no MCP server named "{name}" — connections are built from mcp.json at startup, so the list you are holding may be stale. Refresh and look again.
269
273
  skill_unknown: No skill named "{name}" — the capability page list may be stale. Refresh and look again.
270
274
  provider_unknown: No provider named "{name}" is supported — the selectable set is a fixed list, so the one you are holding may be stale. Refresh and look again.
275
+ provider_key_not_applicable: '{name} does not use an API key — one stored here would never be read, and that provider already works as is'
276
+ provider_key_empty: No key received — paste it into the box and save. (There is no way to revoke an already-stored key from here yet; delete it from ~/.epoch or your keychain.)
271
277
  mcp_add_lan_exposed: 'MCP servers cannot be added in this mode — the server was bound outside the loopback interface with --host, so we cannot tell whether the browser sending this request is on this machine. Adding one writes "which executable to launch" into mcp.json; that server is started right away, and every future epoch run on this machine (including the CLI and the TUI) starts it too. Two ways forward: edit that file directly on the machine running the server, or drop --host and restart.'
272
278
  mcp_add_bad_transport: Transport must be one of stdio / sse / http
273
279
  mcp_add_bad_name: The server name "{name}" cannot be used — it becomes part of the tool name verbatim, so only names starting with a letter or digit and made of letters, digits, _ and - are accepted (48 max). A hand-written mcp.json is not subject to this; only names added from the UI are.
@@ -301,6 +307,17 @@ web:
301
307
  reference_store_unavailable: This machine has no session database (SQLite did not come up), so no historical session can be referenced
302
308
  file_candidates_no_workspace: This session has no workspace bound, so no file list can be offered — pick a directory from the bar under the input box first
303
309
  file_list_unavailable: The workspace file list could not be produced (no .git and not a readable directory), so completion is unavailable — typing the path still attaches the file
310
+ file_view_no_workspace: This session has no workspace bound, so no file can be shown — pick a directory from the bar under the input box first
311
+ file_view_missing_path: No file was named (path is missing)
312
+ file_view_denied: That file is outside the workspace, or a permission rule blocks it — what the model cannot read is not readable here either
313
+ file_view_missing: That file is no longer there
314
+ file_view_not_a_file: That is a directory, not a file
315
+ file_view_unreadable: That file could not be read (permission bits, a write in progress, or a disk problem)
316
+ file_view_too_large: That file is too large to view in place (limit {max} bytes) — open it with the default app, or download it
317
+ file_view_not_text: That is not a text file, so there is no body to fetch — images, PDFs and media go through the bytes route
318
+ file_open_extension_not_allowed: That kind of file is not handed to a system app — code and text are viewable in place, and "opening" an archive would extract it
319
+ file_open_not_same_machine: This browser is not on the machine running the server, so any window would open on someone else screen
320
+ file_open_launch_failed: The system app did not start
304
321
  ui:
305
322
  conn:
306
323
  connecting: Connecting
@@ -327,10 +344,14 @@ web:
327
344
  cav_no_tools: switched, but {model} does not support tool calls — it can only chat, and cannot read or write files
328
345
  pick_provider: Provider
329
346
  pick_provider_none: Pick one…
347
+ pick_model: Model name
348
+ suggest_open: See which models were found
330
349
  provider_no_key: '{label} (no key configured)'
331
350
  probe_probing: Asking {provider} which models it has… no need to wait — you can just type one above.
332
351
  probe_no_key: No key configured for {provider}, so its model list cannot be fetched. Set {env}, or run epoch model.
333
352
  probe_no_key_bare: No key configured for {provider}, so its model list cannot be fetched. Run epoch model to set one up.
353
+ probe_no_key_here: No key configured for {provider}, so its model list cannot be fetched — fill in the API Key box above.
354
+ key_goto: Configure it in settings
334
355
  probe_failed_cache: Could not reach {provider} (network / bad key / that base URL has no /models). Below is what was fetched last time, which may be stale — you can also just type a name.
335
356
  probe_failed_static: Could not reach {provider} (network / bad key / that base URL has no /models). Below is the built-in list, which may be stale — you can also just type a name.
336
357
  probe_empty: '{provider} returned no model names at all, and the built-in list is empty too — just type one.'
@@ -338,11 +359,22 @@ web:
338
359
  suggest_note: These are fetched suggestions, not the full set — new or self-hosted models will not be here. You can still just type one.
339
360
  refresh: Re-fetch
340
361
  refresh_hint: Bypass the cache and ask this provider again
362
+ key_label: API Key
363
+ key_placeholder: Paste a key here
364
+ key_save: Save key
365
+ key_saving: Saving key…
366
+ key_show: Show
367
+ key_hide: Hide
368
+ key_has: 'Configured: {hint} ({env}). Saving a new one overwrites it.'
369
+ key_none: This key goes into the system keychain when one is available, otherwise into ~/.epoch/.env (mode 0600). It is stored as {env}.
370
+ key_saved_secure: Stored in {backend} (encrypted). The model list has been re-fetched with the new key.
371
+ key_saved_plain: ⚠️ The system keychain was unavailable, so this key was stored in plaintext at {path} (mode 0600). Anyone who can read that file on this machine has the key.
341
372
  newsession:
342
373
  open: New session
343
374
  dirpick:
344
375
  back: Back
345
376
  anchors: Common places
377
+ anchors_detail: Home, the server process directory, and workspaces you have visited
346
378
  up: Up one level
347
379
  loading: Loading…
348
380
  empty: No subdirectories here — pick this one, or type a path below
@@ -350,7 +382,10 @@ web:
350
382
  show_hidden: Show hidden directories (starting with .)
351
383
  show_hidden_count: Show hidden directories (starting with ., {count} here)
352
384
  unreadable: 'no permission to enter this directory: {path}'
353
- into: Enter {name}
385
+ into_of: Enter {name} ({path})
386
+ use: Use {name}
387
+ use_here: Use this folder
388
+ use_here_of: 'Use this folder: {path}'
354
389
  known: visited
355
390
  manual_label: Or type an absolute path
356
391
  manual_hint: e.g. /Users/you/work/repo
@@ -363,14 +398,10 @@ web:
363
398
  title: What would you like to do?
364
399
  sidebar:
365
400
  search: Search sessions
366
- capability: Identities · Skills · Connectors
367
- plugins: Plugins
368
401
  automation: Automation
369
402
  automation_pending: '{count} scheduled tasks are missing a grant; they will stall again on the next run'
370
403
  settings: Settings
371
- session: Session
372
- usage_session: Session usage
373
- usage_run: Last run usage
404
+ host_menu: Host menu
374
405
  cost: Spend
375
406
  cost_of: ~${spent} / ${limit}
376
407
  cost_est: Estimate
@@ -386,6 +417,7 @@ web:
386
417
  running: Running
387
418
  updated_at: Last active
388
419
  count: '{count} sessions'
420
+ new_in_space: New session in “{name}”
389
421
  empty: No sessions yet
390
422
  no_match: No matching sessions
391
423
  acts: Actions for “{title}”
@@ -457,6 +489,18 @@ web:
457
489
  clip_lines: Only the first {shown} lines are shown; this file has {total} lines.
458
490
  clip_chars: Cut off on line {line} — that line is too long. This file has {total} lines.
459
491
  binary_note: These files cannot be viewed here — open them with the program your system uses.
492
+ file:
493
+ loading: Opening…
494
+ denied: That file is outside the workspace, or a permission rule blocks it — what the model cannot read is not viewable here either.
495
+ missing: That file is no longer there.
496
+ not_a_file: That is a directory, not a file.
497
+ too_large: That file is too large to view here.
498
+ unreadable: That file could not be read.
499
+ no_answer: The server gave no answer for that path.
500
+ no_session: No session yet, so no file can be shown.
501
+ opaque: The browser cannot render this kind of file. Open it with the default app on your machine, or download it.
502
+ open_with_app: Open with default app
503
+ download: Download
460
504
  plan:
461
505
  empty: No approved plan in this session yet
462
506
  empty_hint: A plan the model hands in has to be approved once on the panel above the composer; only the approved one stays here.
@@ -506,7 +550,7 @@ web:
506
550
  dismiss: Got it
507
551
  session_gone: This conversation is gone on the server — most likely it restarted, and a restart starts a fresh session. This one is not coming back, but you can pick up in the new one.
508
552
  session_gone_open: Go to the current session
509
- session_gone_stuck: This conversation is gone on the server, and right now it cannot even tell us which session is still usable — the server process has most likely stopped. Check on it in your terminal.
553
+ session_gone_stuck: This conversation is gone on the server.
510
554
  thread:
511
555
  thinking_label: Reasoning
512
556
  head_estimate: expected {tokens} tokens
@@ -539,6 +583,8 @@ web:
539
583
  art_no_file: Not spooled to disk — this artifact cannot be opened.
540
584
  art_download: Download {name}
541
585
  art_download_any: Download this artifact
586
+ user_image_alt: Image attached to this message ({mediaType})
587
+ user_image_alt_any: Image attached to this message
542
588
  expand: Expand {count} more lines
543
589
  collapse: Collapse
544
590
  todo_title: Delivery checklist
@@ -662,6 +708,7 @@ web:
662
708
  stalled: “{title}” was going in circles and stopped
663
709
  aborted: “{title}” was stopped mid-run
664
710
  filtered: “{title}” was refused by the model
711
+ compliance: “{title}” ran into a content compliance limit
665
712
  budget: “{title}” hit the budget cap and stopped early
666
713
  failed: “{title}” hit an error
667
714
  go: View
@@ -686,6 +733,9 @@ web:
686
733
  placeholder_gone: This conversation is gone on the server; there is nothing to send to
687
734
  hint_queue: to queue
688
735
  send: Send
736
+ usage_session: Session
737
+ usage_run: Last run
738
+ usage_detail: '{scope} usage: {up}↑ {down}↓'
689
739
  commands_label: Slash commands
690
740
  command_warnings: 'A few things to know about how /{name} expanded:'
691
741
  builtin_notice: /{name}
@@ -705,7 +755,8 @@ web:
705
755
  workspace_pick_note: The list is the directories recently used on this machine. To start a session somewhere new, run epoch there once first.
706
756
  workspace_browse: Open a local folder…
707
757
  workspace_browse_detail: Walk down to a directory, or type an absolute path (lists directories on the machine running epoch)
708
- permission: '{level} permissions'
758
+ workspace_browse_native: Opens a system dialog (on the machine running epoch)
759
+ permission: 'Permissions: {level}'
709
760
  plan_mode: Plan mode
710
761
  plan_on_hint: 'Enter plan mode: the model researches read-only and hands you a plan to approve; it touches no files meanwhile'
711
762
  plan_off_hint: Leave plan mode and go back to the permission level you were on
@@ -757,6 +808,10 @@ web:
757
808
  lvl_bypass: Skip every check
758
809
  lvl_bypass_detail: Nothing is ever asked, and the whole rail turns red
759
810
  blocked_managed: This machine has enterprise managed settings, and they turn off the "Skip every check" level. See Settings › Security centre for details
811
+ keep_env_pinned: 'This level applies to the current run only: EPOCH_PERMISSION overrides it, so the next start will use that instead'
812
+ keep_unwritable: 'This level applies to the current run only: your config file''s layout isn''t one this path recognises, so it was left alone'
813
+ keep_io: 'This level applies to the current run only: the config file could not be written (read-only disk, or no permission)'
814
+ keep_no_config: 'This level applies to the current run only: this process cannot tell where your user config file is'
760
815
  fatal:
761
816
  unauthorized: No access credential
762
817
  unauthorized_hint: Go back to the terminal running epoch web and reopen the tokenised URL it printed.
@@ -768,6 +823,7 @@ web:
768
823
  pane_model: Model & provider
769
824
  pane_memory: Memory & context
770
825
  pane_spend: Usage & spend
826
+ history_only: 'This session is history only — no engine is running it yet. Opening an old session just replays the conversation; the engine is built when you send your next message. This pane asks that engine for its current state, so there is nothing to show yet: go back to the session, send a message, and it will be picked back up.'
771
827
  pane_budget: Budget
772
828
  pane_tools: Tools
773
829
  pane_about: About
@@ -793,8 +849,6 @@ web:
793
849
  none_recorded: This conversation has run, but the per-turn records were never written down (the session predates the change that records them). The numbers will not come back.
794
850
  g_total: Totals
795
851
  g_turns: Per turn
796
- total: Across {turns} turns, {tokens} tokens in total, about {cost}.
797
- total_tokens: Across {turns} turns, {tokens} tokens in total.
798
852
  total_unmeasured: This session ran {turns} turns, but no usage was ever reported, so there is not even a token total.
799
853
  partial: The amount above only covers {priced} of those turns — the other {unpriced} reported usage, but the model they ran on has no pricing data. In the table below they are the rows with an empty cost cell.
800
854
  unknown: 'The amount is unknown, not zero: the models used in these turns have no pricing data on this machine, so only the provider knows how much was really spent.'
@@ -805,7 +859,7 @@ web:
805
859
  tok_output: Output
806
860
  tok_reasoning: 'Of which reasoning: {n}. It is already included in the number above.'
807
861
  tok_cache_note: Cache hits are priced separately, usually far below the full rate — the more hits, the cheaper the same amount of context.
808
- col_turn: Turn
862
+ col_turn: Turns
809
863
  col_model: Model
810
864
  col_tokens: Tokens
811
865
  col_cost: Cost
@@ -820,6 +874,7 @@ web:
820
874
  why: Why this value
821
875
  chain_win: wins
822
876
  g_other: Other
877
+ overridable_sum: Which keys upper layers can override
823
878
  overridable: 'Only these keys can be overridden by the project, project-local, command-line or managed layers: {keys}. Every other setting has just two layers, built-in and user — putting one in .epoch/settings.json does nothing, and startup diagnostics will report it as an unknown config key.'
824
879
  overridable_perm: The permissions entry on that list is three lists (allow / ask / deny) merged as a union rather than an override, so its provenance is per rule — see Security › Permission rules.
825
880
  managed_locked: This one is set by the managed settings on this machine; changing it at the user or project level has no effect. That file is not writable by an ordinary user — ask an administrator.
@@ -828,12 +883,13 @@ web:
828
883
  save: Save
829
884
  new_value: New value
830
885
  write_layer: Write to
886
+ write_file: Into file
831
887
  dirty: Unsaved
832
888
  futile_shadowed: 'Writing to {layer} will have no effect: {by} sets this too, and it ranks higher, so on load it overrides what you write here. To make it take effect, write to {by} or above.'
833
889
  futile_untrusted: 'This workspace is not trusted yet, so settings in {layer} are dropped wholesale on load (deny rules are the one exception) — writing there does nothing. Trust the directory under Security › Workspace & trust first, or write to the user layer instead: it does not go through the trust gate.'
834
890
  wrote: 'Written to {layer}: {value}'
835
891
  wrote_stale: This process read the config once at startup and never re-reads it, so it is still using {value} — restarting epoch web is what switches it to the value you just wrote. Starting a new session will not do it either; the config is one per process.
836
- lede_model: 'The model and provider this process is using right now. To change: edit ~/.epoch/config.yaml, or run epoch model.'
892
+ lede_model: The model this process is using right now. Changing a row here writes to ~/.epoch/config.yaml. The provider and API key are not on this screen — run epoch model for those.
837
893
  k_model: Main model
838
894
  k_models_utility: Utility model
839
895
  h_models_utility: Used for chores like compacting context and titling sessions. Unset means everything goes to the main model.
@@ -841,7 +897,7 @@ web:
841
897
  k_fallback_providers: Fallback chain
842
898
  h_fallback_providers: Tried in this order when the main provider is unreachable.
843
899
  lede_memory: The first two decide how much fits in a turn and how many steps it may take; the last two decide what happens when it no longer fits. Setting a context window larger than the model really has buys you a 400.
844
- k_context_length: Context window
900
+ k_context_length: Context window (tokens)
845
901
  h_context_length: Only used as a fallback when the model metadata cannot be read; when it can, metadata wins and a configured value has no effect. The compression line below uses the window the engine actually runs on.
846
902
  k_max_turns: Max steps per turn
847
903
  h_max_turns: How many tool calls the model may make in one turn. On reaching the cap it stops and finishes its answer.
@@ -852,8 +908,7 @@ web:
852
908
  ctx_line: With this configuration, compaction starts once the prompt reaches {tokens} tokens — {percent}% of the {window}-token context window.
853
909
  ctx_line_caveat: That is the line itself. Just after a compaction, or once several compactions in a row have failed, crossing it will not compact yet.
854
910
  ctx_off: Auto-compaction is off. When a long session hits the context window there is no automatic rescue — that turn simply fails, and the context does not shrink on its own. Manual /compact is unaffected by this switch and still works.
855
- ctx_no_switch: 'These two rows cannot be changed here, same as the two above: only three keys can be overridden by project-level config (the list below), and compaction is not one of them — otherwise a repository could quietly let long sessions opened inside it run into the window. Change it by editing ~/.epoch/config.yaml yourself:'
856
- ctx_restart: Restart the epoch web process for this to take effect — it reads the config once at startup and never re-reads it.
911
+ ctx_not_overridable: 'These two rows can only be written to the user level: only three keys can be overridden by project-level config (the list below), and compaction is not one of them — otherwise a repository could quietly let long sessions opened inside it run into the window.'
857
912
  budget_title: Where it is going right now
858
913
  budget_used: '{used} used — {percent}% of the {limit} window.'
859
914
  budget_used_only: '{used} used. This model has no known context window, so there is no percentage to report.'
@@ -863,13 +918,21 @@ web:
863
918
  budget_compacting: Compacting…
864
919
  budget_compact_hint: Rewrites earlier messages into a summary to free up window for what comes next. It sends one model request (so it costs money), but not a single line of this conversation is removed — only what gets sent to the model next turn changes.
865
920
  lede_budget: Amounts only appear in the UI once a cap is configured. With no cap these rows read "Not set", which is also the default.
866
- k_budget_max_cost: Spend cap
921
+ k_budget_max_cost: Spend cap (USD)
922
+ h_budget_max_cost: 'Accumulates per session — not a per-request cap — and --resume picks the count back up. The turn that crosses the line is not charged first and reported after: the gate stops it before the next request goes out.'
867
923
  k_budget_max_tokens: Token cap
868
924
  h_budget_max_tokens: With both rulers configured, the gate reports whichever is tighter.
869
925
  k_budget_warn_at: Warn at
870
926
  h_budget_warn_at: Percent. Warns once, on crossing — not every turn.
871
927
  k_budget_unknown_pricing: When the model has no pricing data
872
928
  h_budget_unknown_pricing: block stops the call, warn lets it through with a warning. With no pricing data the cost is "unknown", not 0, and the two must be handled separately.
929
+ ex_budget_max_cost: e.g. 5
930
+ ex_budget_max_tokens: e.g. 1000000
931
+ ex_budget_warn_at: e.g. 80
932
+ blocked_empty: This cannot be empty. Clearing it is not the same as removing the setting — this path has no delete-key at all; to get the default back, delete that line in the file named above.
933
+ blocked_pick: Pick one from the row above.
934
+ blocked_number: This takes a number, and "{text}" does not read as one. No unit, no thousands separators.
935
+ blocked_boolean: This takes exactly true or false — those are the two literals that go into the yaml.
873
936
  sec:
874
937
  lede: What this agent can touch right now, and what is holding it back.
875
938
  no_session: 'No session yet. Three things here are bound per session: the workspace, its trust verdict, and the project-level policy directory that follows that trust — with no session there is no "which one" to answer.'
@@ -993,7 +1056,7 @@ web:
993
1056
  audit_code_headless_unauthorized: Non-interactive, not pre-authorized
994
1057
  audit_code_user_approved: You approved it
995
1058
  audit_code_user_denied: You denied it
996
- perm_where: 'Change the top one from the row under the composer it takes effect immediately. The bottom one is where new sessions start: edit ~/.epoch/config.yaml and restart.'
1059
+ perm_where: 'Both come from the row under the composer: picking a level takes effect immediately and is recorded as the starting point below (written to ~/.epoch/config.yaml), which new sessions and the next start begin from.'
997
1060
  perm_now: Now
998
1061
  perm_default: Default
999
1062
  perm_now_changed: (changed in this session)
@@ -1065,7 +1128,7 @@ web:
1065
1128
  skill_unindexed: not in the index
1066
1129
  skills_capped_note: '{count} skills are held out of the index by `skills.maxIndexed`: they cost nothing per turn, and the model cannot list them either. Raise or remove that setting to get them back.'
1067
1130
  skills_role_note: '{count} skills are outside this session identity''s skill allowlist, so they are not indexed. ⚠️ That is not a lock: the bodies stay readable — narrowing is a context budget, not reachability.'
1068
- no_toggle: 'There is no "turn this skill off" switch: as long as the file is in the directory, it gets picked up. To drop one, move its directory away; to just save context, `skills.maxIndexed` caps the index.'
1131
+ no_toggle: 'There is no "turn this skill off" switch: as long as the file is in the directory, it gets picked up. To drop one, use Delete on its row — that removes its directory for good; to just save context, `skills.maxIndexed` caps the index.'
1069
1132
  import_entry: Import a skill
1070
1133
  import_title: Import a skill
1071
1134
  import_lede: Import from the machine running the server. Accepts a folder containing SKILL.md, a two-level category/name skill tree, a .zip of either, or a single .md with frontmatter.
@@ -1096,6 +1159,11 @@ web:
1096
1159
  skill_view_no_count: Looking at this will not affect its score — that tally only counts times the model actually used it.
1097
1160
  skill_truncated: This SKILL.md is large ({bytes} bytes in total); below is only the first stretch of it. Open the file directly to read the whole thing.
1098
1161
  skill_bytes: '{bytes} bytes in total'
1162
+ skill_remove: Delete
1163
+ skill_remove_ask: Delete {name}? Its whole directory goes with it, and this cannot be undone.
1164
+ skill_remove_yes: Delete
1165
+ skill_cancel: Cancel
1166
+ skill_removed: 'Deleted {name}. This is the directory that was just removed:'
1099
1167
  plugins: Plugins
1100
1168
  plug_lede: 'A plugin is a bundle of extensions: slash commands, identities, skills, hooks, deny rules, MCP servers. Pick one from a marketplace already added on this machine — this page can only pick from that list; it cannot take a path and cannot upload a file.'
1101
1169
  plug_installed_head: Installed ({count})
@@ -1297,6 +1365,9 @@ web:
1297
1365
  how_to_block: To block a tool, add a deny rule to the permission table. Rules only count once they are in a config file, and this interface never writes config — the security centre shows which rules exist today and which layer each came from.
1298
1366
  goto_rules: Open the rule table
1299
1367
  mcp_note: Tools from MCP servers are in this table too, named mcp__<server>__<tool>. The Source column says which server each one came from.
1368
+ tip:
1369
+ what: What this is
1370
+ about: About {name}
1300
1371
  about:
1301
1372
  loading: Reading…
1302
1373
  lede: When something goes wrong, paste a screenshot of this into the issue — it beats describing the symptoms.
@@ -1422,15 +1493,26 @@ web:
1422
1493
  remove_confirm: Delete "{name}"? Its registration in the OS scheduler goes with it. Run recordings are kept.
1423
1494
  form_new: New scheduled task
1424
1495
  form_edit: Edit scheduled task
1496
+ g_what: What it does
1497
+ g_what_note: The thing it runs when the time comes
1498
+ g_where: Where it runs
1499
+ g_where_note: Both optional — each has a definite default
1500
+ g_when: When it runs
1501
+ g_may: What it may do
1502
+ g_may_note: This group decides which confirmations it presses for you at night
1503
+ g_cost: How much it may spend
1504
+ g_cost_note: Three limits; hitting any one stops the run
1505
+ required: Required
1425
1506
  f_name: Name
1426
1507
  f_prompt: Prompt
1427
1508
  f_prompt_hint: What the agent should do when it fires. Say what it should leave behind — nobody will be there to ask.
1428
1509
  f_workdir: Workspace (optional)
1429
- f_workdir_hint: Absolute path on the server
1430
- f_workdir_note: Left empty, it runs in ~/.epoch/automation/<task id>/. It does **not** inherit any terminal's current directory.
1510
+ f_workdir_note: Left empty, it runs in ~/.epoch/automation/<task id>/. It never inherits any terminal's current directory.
1431
1511
  f_workdir_default: ~/.epoch/automation/<task id>/
1512
+ f_workdir_none: No specific workspace
1432
1513
  f_model: Model (optional)
1433
1514
  f_model_hint: Empty uses the configured one
1515
+ f_model_provider_note: Whichever provider you pick is saved with the task and used when it fires. If that provider has no key on this machine at fire time, the run falls back to the default model and records a line about it.
1434
1516
  f_kind: Frequency
1435
1517
  k_daily: Daily
1436
1518
  k_weekly: Weekly
@@ -1446,11 +1528,14 @@ web:
1446
1528
  f_days_note: The 31st does not fire in short months — that is the native behaviour on both platforms.
1447
1529
  f_start: Active from (optional)
1448
1530
  f_end: Active until (optional)
1531
+ f_window_note: Both ends are inclusive. Leave an end blank and that end is unbounded. Firings that fall outside the range are recorded as "skipped (outside active range)" and are not made up later.
1532
+ f_window_once: A run-once task cannot carry an active range — it already is a single date, so these two cannot be filled in on this kind.
1449
1533
  f_permission: Permission level
1450
1534
  f_bypass_ack: 'I understand: this task will do anything without asking inside {workDir}, including deleting files and running arbitrary commands.'
1451
1535
  f_turns: Max turns
1536
+ f_turns_hint: How many times the model may call a tool in one turn, 1 to 1000. On hitting the cap it stops and finishes its answer.
1452
1537
  f_timeout: Timeout (minutes)
1453
- f_timeout_note: The only ruler that catches "a command hung" — turns and spend both stop growing there.
1538
+ f_timeout_note: The only ruler that catches "a command hung" — turns and spend both stop growing there. 24 hours at most.
1454
1539
  f_budget: Max spend per run (USD)
1455
1540
  f_budget_why: 'Required, and we give no default: nobody is watching this task, and a fake default would make "woke up to $40" our fault.'
1456
1541
  save_and_run: Save and run once
@@ -1800,6 +1885,8 @@ skill:
1800
1885
  import_bad_name_dots: A skill name cannot be . or ..
1801
1886
  import_bad_name_char: 'The skill name "{name}" contains characters that cannot be used in a directory name (< > : " / \ | ? * and control characters). The colon in particular separates the plugin/host prefix — a user-level skill taking it would masquerade as a plugin skill'
1802
1887
  import_bad_name_trailing: The skill name "{name}" ends with a dot or a space — on Windows such a directory can be created but not opened
1888
+ remove_no_system: The skill system did not start this run — no skills are loaded in this process, so there is nothing to delete. Check the Skill entries in the startup diagnostics
1889
+ remove_unknown: There is no skill named "{name}" — the list you are looking at may be stale; refresh it
1803
1890
  host_capabilities:
1804
1891
  loaded: '{namespace}: {roles} identity/identities, {skillDirs} skill directory/directories, {mcpServers} MCP server(s), {tools} tool(s) (the first two get the {namespace}: prefix, the last two get {namespace}__ — both end up inside a tool name, and tool names cannot contain a colon)'
1805
1892
  bad_role_name: Identity "{name}" has an invalid name (lowercase letters, digits and hyphens only, and it may not start with a hyphen); that one was skipped, the rest were injected as usual
@@ -1934,6 +2021,7 @@ mcp_write:
1934
2021
  invalid: the configuration is not valid
1935
2022
  mcp_config:
1936
2023
  invalid_json: 'Nothing was written — this content is not valid JSON: {why}'
2024
+ stale_disk: nothing was written — ~/.epoch/mcp.json changed while this edit was being computed; read it again and redo the change
1937
2025
  role_write:
1938
2026
  bad_name: The identity name "{name}" cannot be used — lowercase letters, digits and hyphens only, and it may not start with a hyphen. This name is both the file name and the word used to delegate work (the `role` argument of delegate_task, the value of --agent), which is why it is validated strictly.
1939
2027
  taken: 'There is already an identity named "{name}" — pick another name. Nothing is overwritten and nothing is auto-renamed here: overwriting would delete the prose you wrote in that file, and renaming would make the word used to delegate work disagree with what you typed.'
@@ -2073,6 +2161,7 @@ provider:
2073
2161
  label_openai_compatible: OpenAI Compatible (generic adapter)
2074
2162
  response_format_with_tools: 'A single request cannot ask for both tools and responseFormat: the model either calls tools or emits one JSON document, pick one'
2075
2163
  response_format_dropped: '{model} did not honour this round''s forced-JSON constraint (the request was still sent), so this round''s output may not be JSON'
2164
+ key_not_applicable: '{provider} does not use an API key — one stored here would never be read'
2076
2165
  utility:
2077
2166
  aborted: This one-shot completion was aborted before it was sent (not sent, not billed)
2078
2167
  terminal_setup:
@@ -3125,6 +3214,7 @@ untrusted:
3125
3214
  skipped: The workspace is not trusted, so project {what} were not loaded (epoch trust can trust this directory)
3126
3215
  what_commands: commands
3127
3216
  what_policy: policy rules
3217
+ what_compliance: compliance lexicons
3128
3218
  what_skills: skills
3129
3219
  what_roles: roles
3130
3220
  hooks_tail: The workspace is not trusted, so project hooks were not loaded (epoch trust can trust this directory) — hooks run commands, and there is no "the narrowing part still applies" exception here
@@ -3181,6 +3271,40 @@ policy_load:
3181
3271
  not_kv: 'Neither [[rule]] nor key = "value"; ignored: {preview}'
3182
3272
  before_first_rule: '{key} appears before the first [[rule]]; ignored'
3183
3273
  rule_skipped: '{message}; this rule was skipped'
3274
+ compliance_cmd:
3275
+ cmd_root: Self-check for the content compliance gate
3276
+ cmd_check: Check whether a piece of text would be blocked, and which characters matched
3277
+ cmd_status: Show the current state on this machine (switches, rule counts, per-category action)
3278
+ arg_text: the text to check
3279
+ opt_stdin: read from standard input (useful for checking a whole file)
3280
+ need_text: Check what? Pass some text, or add --stdin to read from standard input
3281
+ disabled: 'Content compliance is not enabled (compliance.enabled: false), so nothing is checked'
3282
+ clean: 'Clean: nothing matched'
3283
+ verdict: 'Verdict: {action}, {count} matches'
3284
+ hit: ' [{category}] {action} <- {excerpt} (rule {rule})'
3285
+ blocked: 'This is the block tier: on the input side the request is never sent (and never billed); with the output side enabled, the sentence that matched never reaches the screen'
3286
+ released: 'After filtering: {text}'
3287
+ status_enabled: 'Enabled: {enabled}'
3288
+ status_rules: 'Rules: {active} active ({builtin} built-in + {user} from your lexicons)'
3289
+ status_dir: 'User lexicon directory: {dir}'
3290
+ status_scope: 'Channels: output {output} / input {input} / skip code {code}'
3291
+ status_action: ' {category} -> {action}'
3292
+ status_project_note: 'Note: project-level lexicons (<project root>/.epoch/compliance/) go through the workspace trust gate, and this command does not read them — a real session does'
3293
+ compliance:
3294
+ category_sep: ', '
3295
+ category:
3296
+ sexual: sexual content
3297
+ political: political / national security
3298
+ hate: ethnic or racial discrimination
3299
+ violence: violence and terrorism
3300
+ illegal: illegal activity
3301
+ self_harm: self-harm
3302
+ privacy: personal sensitive data
3303
+ compliance_load:
3304
+ dir_read_failed: 'Could not read the compliance lexicon directory: {reason}'
3305
+ file_read_failed: 'Could not read it, so the whole file was skipped: {reason}'
3306
+ unknown_file: 'The file name is not a category name, so the whole file was skipped. Known categories: {categories} (regexes go in <category>.regex.txt, exemptions in exempt.txt)'
3307
+ bad_regex: 'The regex did not compile, so this entry was skipped: {reason}'
3184
3308
  skill_load:
3185
3309
  degraded: '{message}; loaded as if it had no frontmatter'
3186
3310
  not_a_map: The frontmatter is not key/value pairs (the top level has to be a YAML object); loaded as if it had no frontmatter
@@ -3283,7 +3407,12 @@ context_breakdown:
3283
3407
  agent_run:
3284
3408
  error: 'Error: {message}'
3285
3409
  images_unsupported: The current model does not support image input, so this request was cancelled (not sent, not billed). Switch to a vision-capable model (gpt-4o / claude-sonnet-4-6 / gemini-2.5-flash), or drop the {count} images and retry.
3410
+ images_dropped: '{provider} dropped the {count} images in this turn (its own words: {feature}), so the model never saw them — do not trust this turn''s answer. The request was sent and billed. Most likely this provider''s SDK version cannot carry images yet, or this model does not actually accept them.'
3411
+ images_dropped_provider_unknown: The current provider
3286
3412
  content_filter: The model refused to respond for safety reasons; try asking a different way.
3413
+ compliance_output: This reply ran into a content compliance limit ({categories}), so output stopped.
3414
+ compliance_input: Your message ran into a content compliance limit ({categories}); the request was not sent and nothing was billed.
3415
+ compliance_input_masked: Your message contained wording that runs into a content compliance limit ({categories}), so it was masked before being sent — the model did not see the text exactly as it appears on your screen.
3287
3416
  stalled: 'Detected a loop: {info}. The task was terminated.'
3288
3417
  stall_info: '{tool}({args}) was called {count} turns in a row, which looks like a loop'
3289
3418
  max_turns: Reached the maximum of {max} turns; the task was terminated unfinished.
@@ -3472,6 +3601,7 @@ secret:
3472
3601
  infra_misc:
3473
3602
  shell_not_on_path: 'shell: the configured {kind} ({exe}) is not on PATH; fell back to cmd.exe'
3474
3603
  ripgrep_install_windows: winget install BurntSushi.ripgrep.MSVC (or scoop install ripgrep)
3604
+ ripgrep_chmod_hint: chmod +x "{path}" — prefix with sudo if that directory is root-owned
3475
3605
  schema_failed: '{path} failed validation ({count} problems):\n{detail}'
3476
3606
  schema_more: '{count} more problems not listed'
3477
3607
  schema_unknown_key: Unknown setting, ignored (other settings still apply)
@@ -3517,6 +3647,9 @@ boot:
3517
3647
  managed_hooks_only: Managed enterprise settings turned on allowManagedHooksOnly, so neither user-level nor project-level hooks load ({path})
3518
3648
  policy_load_failed: loading failed (skipped)
3519
3649
  perm_rules: '{total} permission rules (allow {allow} / ask {ask} / deny {deny})'
3650
+ compliance_ready: '{active} rules active ({builtin} built-in + {external} from lexicon files)'
3651
+ compliance_off: 'not enabled (compliance.enabled: false)'
3652
+ compliance_load_failed: the external lexicons could not be loaded, so only the built-in seed list is in use
3520
3653
  commands_all_failed: None of the {count} files could be loaded, so there are no usable custom commands
3521
3654
  command_allowed_tools: '{tools} in the allowed-tools of {name} do not exist and were ignored'
3522
3655
  tools_cost: '{count} tools ({split}) ≈ {tokens}k tokens/turn'
@@ -3526,6 +3659,7 @@ boot:
3526
3659
  shell_kind: '{kind} (terminal tool commands are handed to it)'
3527
3660
  plugin_register_failed: registration failed ({reason})
3528
3661
  ripgrep_missing: not installed, so file_search is unavailable ({hint})
3662
+ ripgrep_not_executable: shipped but not executable, so file_search is unavailable for now ({hint})
3529
3663
  ripgrep_system: using the system rg
3530
3664
  ripgrep_builtin: using the bundled rg{version}
3531
3665
  mcp_none: not configured (~/.epoch/mcp.json is missing or empty)