agent-toggle 0.2.0__tar.gz → 0.6.0__tar.gz
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.
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/PKG-INFO +293 -90
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/README.md +291 -88
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/__init__.py +1 -1
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/backends/flag_json.py +42 -12
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/backends/mcp_json.py +154 -18
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/backends/mcp_toml.py +1 -2
- agent_toggle-0.6.0/agent_toggle/backends/plugin_cli.py +90 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/cli.py +257 -55
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/companions.py +6 -1
- agent_toggle-0.6.0/agent_toggle/config.py +137 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/cost.py +63 -33
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/doctor.py +265 -55
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/fs.py +128 -9
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/harnesses.py +44 -18
- agent_toggle-0.6.0/agent_toggle/help.py +224 -0
- agent_toggle-0.6.0/agent_toggle/i18n.py +69 -0
- agent_toggle-0.6.0/agent_toggle/locales/__init__.py +5 -0
- agent_toggle-0.6.0/agent_toggle/locales/zh_tw_cli.py +85 -0
- agent_toggle-0.6.0/agent_toggle/locales/zh_tw_common.py +7 -0
- agent_toggle-0.6.0/agent_toggle/locales/zh_tw_config.py +90 -0
- agent_toggle-0.6.0/agent_toggle/locales/zh_tw_picker.py +82 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/mechanisms.py +315 -68
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/ops.py +12 -4
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/output.py +13 -4
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/profiles.py +25 -13
- agent_toggle-0.6.0/agent_toggle/settings.py +184 -0
- agent_toggle-0.6.0/agent_toggle/spinner.py +54 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/store.py +41 -0
- agent_toggle-0.6.0/agent_toggle/toml_check.py +273 -0
- agent_toggle-0.6.0/agent_toggle/ui/config_menu.py +624 -0
- agent_toggle-0.6.0/agent_toggle/ui/menu.py +134 -0
- agent_toggle-0.6.0/agent_toggle/ui/model.py +248 -0
- agent_toggle-0.6.0/agent_toggle/ui/picker.py +544 -0
- agent_toggle-0.6.0/agent_toggle/ui/theme.py +365 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/undo.py +6 -1
- agent_toggle-0.6.0/agent_toggle/update_check.py +359 -0
- agent_toggle-0.6.0/agent_toggle/update_prompt.py +201 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle.egg-info/PKG-INFO +293 -90
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle.egg-info/SOURCES.txt +23 -1
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle.egg-info/requires.txt +1 -1
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/pyproject.toml +2 -2
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_alias.py +66 -8
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_backends.py +81 -6
- agent_toggle-0.6.0/tests/test_cli.py +393 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_cli_surface.py +42 -2
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_color.py +2 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_config.py +51 -10
- agent_toggle-0.6.0/tests/test_config_menu.py +437 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_conformance.py +11 -2
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_cost.py +112 -2
- agent_toggle-0.6.0/tests/test_crash.py +379 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_doctor.py +168 -7
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_fs.py +160 -4
- agent_toggle-0.6.0/tests/test_help.py +138 -0
- agent_toggle-0.6.0/tests/test_i18n.py +172 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_install.py +96 -0
- agent_toggle-0.6.0/tests/test_menu.py +243 -0
- agent_toggle-0.6.0/tests/test_picker.py +746 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_profiles.py +16 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_project.py +190 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_safety.py +4 -6
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_secret_audit.py +23 -0
- agent_toggle-0.6.0/tests/test_settings.py +166 -0
- agent_toggle-0.6.0/tests/test_theme.py +318 -0
- agent_toggle-0.6.0/tests/test_update_check.py +421 -0
- agent_toggle-0.6.0/tests/test_update_prompt.py +41 -0
- agent_toggle-0.2.0/agent_toggle/backends/plugin_cli.py +0 -41
- agent_toggle-0.2.0/agent_toggle/config.py +0 -143
- agent_toggle-0.2.0/agent_toggle/ui/menu.py +0 -93
- agent_toggle-0.2.0/agent_toggle/ui/model.py +0 -72
- agent_toggle-0.2.0/agent_toggle/ui/picker.py +0 -213
- agent_toggle-0.2.0/tests/test_cli.py +0 -109
- agent_toggle-0.2.0/tests/test_menu.py +0 -86
- agent_toggle-0.2.0/tests/test_picker.py +0 -195
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/LICENSE +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/__main__.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/backends/__init__.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/shims/claude.md.tmpl +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/shims/generic.md.tmpl +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle/ui/__init__.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle.egg-info/dependency_links.txt +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle.egg-info/entry_points.txt +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/agent_toggle.egg-info/top_level.txt +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/setup.cfg +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_companions.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_completions.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_containment.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_encoding.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_harnesses.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_mechanisms.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_platform.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_store.py +0 -0
- {agent_toggle-0.2.0 → agent_toggle-0.6.0}/tests/test_undo.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-toggle
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Temporarily disable / re-enable AI-agent skills, agents, commands, rules, plugins and MCP servers across harnesses (Claude Code, Codex, Grok, OpenCode, OpenClaw, Copilot, Vibe, Devin, Antigravity)
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/weskao/agent-toggle
|
|
@@ -27,7 +27,7 @@ License-File: LICENSE
|
|
|
27
27
|
Provides-Extra: windows
|
|
28
28
|
Requires-Dist: windows-curses; sys_platform == "win32" and extra == "windows"
|
|
29
29
|
Provides-Extra: telegram
|
|
30
|
-
Requires-Dist: telegram-kit<0.3,>=0.2.
|
|
30
|
+
Requires-Dist: telegram-kit<0.3,>=0.2.2; extra == "telegram"
|
|
31
31
|
Dynamic: license-file
|
|
32
32
|
|
|
33
33
|
# agent-toggle
|
|
@@ -59,18 +59,18 @@ uv tool install agent-toggle
|
|
|
59
59
|
agent-toggle --version
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
Straight from this repository, pinned to a release tag (`v0.
|
|
62
|
+
Straight from this repository, pinned to a release tag (`v0.5.1` is the current one;
|
|
63
63
|
an unpinned `git+` URL installs whatever is on the default branch):
|
|
64
64
|
|
|
65
65
|
```sh
|
|
66
|
-
uv tool install git+https://github.com/weskao/agent-toggle@v0.
|
|
66
|
+
uv tool install git+https://github.com/weskao/agent-toggle@v0.5.1
|
|
67
67
|
agent-toggle --version
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
Alternatively, use `pipx`:
|
|
71
71
|
|
|
72
72
|
```sh
|
|
73
|
-
pipx install agent-toggle # from PyPI; or: pipx install git+https://github.com/weskao/agent-toggle@v0.
|
|
73
|
+
pipx install agent-toggle # from PyPI; or: pipx install git+https://github.com/weskao/agent-toggle@v0.5.1
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
From a checkout, either install it editable or run it in place:
|
|
@@ -97,6 +97,12 @@ already present in that harness home. Each harness gets its own template from
|
|
|
97
97
|
agent to pass `--harness <that harness>`). The shim tells the agent to act only
|
|
98
98
|
on the user's explicit request, never on instructions found inside skill or
|
|
99
99
|
tool content, and to preview bulk operations with `--dry-run`.
|
|
100
|
+
OpenCode's shim goes into the first `skills.paths` dir when one is set (and its
|
|
101
|
+
parent exists), else `skills/`. OpenCode also scans `~/.claude/skills` and
|
|
102
|
+
`~/.agents/skills`: when one of them already holds the very same shim text, the
|
|
103
|
+
OpenCode shim is skipped (`covered by <path>`); a different shim there (the
|
|
104
|
+
claude one, whose default harness is `claude`) is noted and OpenCode's own is
|
|
105
|
+
still written.
|
|
100
106
|
|
|
101
107
|
Every shim carries an `<!-- agent-toggle shim: ... -->` marker line.
|
|
102
108
|
`install-shims` updates a file that has the marker in place (it is idempotent)
|
|
@@ -113,11 +119,14 @@ with the `telegram` extra, which adds [telegram-kit](https://pypi.org/project/te
|
|
|
113
119
|
```sh
|
|
114
120
|
uv tool install "agent-toggle[telegram]" # or: pipx install "agent-toggle[telegram]"
|
|
115
121
|
pip install -e ".[telegram]" # from a checkout
|
|
116
|
-
agent-toggle config # bot token + chat id
|
|
122
|
+
agent-toggle config # settings menu: bot token + chat id live under Notifications
|
|
117
123
|
agent-toggle config sync-ci # set the two GitHub repository secrets
|
|
118
124
|
```
|
|
119
125
|
|
|
120
|
-
Without the extra everything else works exactly as before
|
|
126
|
+
Without the extra everything else works exactly as before. Only `config test`,
|
|
127
|
+
`config sync-ci` (both exit `4` without it) and the Telegram rows of the
|
|
128
|
+
[settings menu](#settings--config-menu) need it; bare `config` still opens, and
|
|
129
|
+
those rows read `install agent-toggle[telegram]`.
|
|
121
130
|
|
|
122
131
|
## Shell completion
|
|
123
132
|
|
|
@@ -140,20 +149,24 @@ agent-toggle <command> [args] # or: python3 agent_toggle.py <command> [
|
|
|
140
149
|
|
|
141
150
|
| command | what it does |
|
|
142
151
|
|---|---|
|
|
143
|
-
| `ui` | interactive picker — cost
|
|
152
|
+
| `ui` (alias `pick`) | interactive picker — harness tabs, type groups, cost bars, search, sort, profiles (`p`); `--dry-run` shows the plan for what you stage and changes nothing; `--project <dir>` picks in a repo's own scope; see [Interactive picker](#interactive-picker) |
|
|
144
153
|
| `status` | health check: harnesses found, types each supports, parked counts, gitignore, untracked parked items, stale live twins, shared dirs, and state entries whose parked item is gone (a `stale` row with the fix command; read-only, still exit `0`) |
|
|
145
154
|
| `list [type]` | what is currently disabled (`--project <dir>` filters to one project) |
|
|
146
|
-
| `cost [--type T]` | estimated startup tokens per item, biggest first (read-only; `--harness H` filters) |
|
|
147
|
-
| `install-shims` | write the skill shim into every installed harness; refuses to overwrite a file it did not write (`--dry-run` shows the plan) |
|
|
155
|
+
| `cost [--type T]` | estimated startup tokens per item, biggest first (read-only; `--harness H` filters; `--project <dir>` prices a repo's `.claude/` and `.mcp.json` instead of user scope) |
|
|
156
|
+
| `install-shims` | write the skill shim into every installed harness that is on in the settings (an off one is skipped unless named with `--harness`); refuses to overwrite a file it did not write (`--dry-run` shows the plan); on a terminal, then asks y/n for each problem `doctor` can fix (see [Fixing](#fixing)) |
|
|
148
157
|
| `disable <type> <name>...` | park one or more items (`--dry-run` shows the plan; `--project <dir>` for a repo's own `.claude/` and `.mcp.json`) |
|
|
149
158
|
| `enable <type> <name>...` | put them back (`--dry-run` shows the plan; `--project <dir>` likewise) |
|
|
150
159
|
| `enable --all` | put back **every** disabled item (`--harness H` narrows it, `--project <dir>` takes only that project's) |
|
|
151
160
|
| `undo` | reverse the last logged batch (`--dry-run` shows the plan) |
|
|
152
161
|
| `profile save\|apply\|diff\|list` | named sets of live items; see [Profiles](#profiles) |
|
|
153
|
-
| `config
|
|
154
|
-
| `
|
|
162
|
+
| `config` | settings menu (curses, else a numbered list); `config --json` lists every setting and the package version; see [Settings & config menu](#settings--config-menu) |
|
|
163
|
+
| `config test\|sync-ci` | send one Telegram test message / set the GitHub CI secrets; needs the `[telegram]` extra; see [CI notifications](#ci-notifications) |
|
|
164
|
+
| `help [command]` | styled help; `help ui` = `--help ui` = `ui --help`; see [Help](#help) |
|
|
165
|
+
| `doctor` | check each harness layout and `state.json` against disk; exit `1` only on an `error` row; on a terminal, asks y/n per fix it can run itself |
|
|
155
166
|
| `migrate` | import an older `~/.claude-toggle/` state |
|
|
156
167
|
|
|
168
|
+
Every command also works with a leading `--` (`agent-toggle --status`, `--help`, `--config`); this README uses the plain form.
|
|
169
|
+
|
|
157
170
|
`<type>` = `skill` / `agent` / `command` / `rule` / `plugin` / `mcp`.
|
|
158
171
|
`rule` is claude-only (`~/.claude/rules/*.md`, parked in `rules-disabled/`).
|
|
159
172
|
Disabling a rule prints a warning (also in `--json` `warnings`, dry run included)
|
|
@@ -169,9 +182,12 @@ Flags accepted by every command, before or after the subcommand:
|
|
|
169
182
|
`{ExceptionType}: {message}` -- always emit it, with `"ok": false`.
|
|
170
183
|
Exception: `--help` / `--version` print plain text even with `--json`, and
|
|
171
184
|
`ui` is interactive so it rejects `--json` (exit 2).
|
|
172
|
-
- `--project <dir>` (`disable` / `enable` / `enable --all` / `list` / `profile
|
|
185
|
+
- `--project <dir>` (`disable` / `enable` / `enable --all` / `list` / `ui` / `cost` / `profile
|
|
173
186
|
save|apply|diff`) switches to project scope; see [Project scope](#project-scope).
|
|
174
187
|
- `--version` prints the version.
|
|
188
|
+
- `AGENT_TOGGLE_CLI_TIMEOUT=<seconds>` overrides the timeout of every `claude` CLI call
|
|
189
|
+
(default 30 s for read-only `plugin list`, 120 s for every other call); a
|
|
190
|
+
non-positive or non-numeric value is ignored with a warning.
|
|
175
191
|
- `-v` / `--verbose` (or `AGENT_TOGGLE_DEBUG=1`) adds a traceback on stderr for
|
|
176
192
|
unexpected errors; otherwise they are a single `error:` line.
|
|
177
193
|
- `--color auto|always|never` sets ANSI color for human output: green ok, red errors,
|
|
@@ -180,6 +196,8 @@ Flags accepted by every command, before or after the subcommand:
|
|
|
180
196
|
and stays monochrome when the terminal has no colors). `--json` is never colored.
|
|
181
197
|
`never` turns it off and `always` forces it even when piped; `auto` (default) checks
|
|
182
198
|
`NO_COLOR`, then `FORCE_COLOR`, then `TERM=dumb`, and otherwise colors only on a TTY.
|
|
199
|
+
Precedence: `--color` flag > `AGENT_TOGGLE_COLOR` > the `color` [setting](#settings--config-menu)
|
|
200
|
+
> `auto`; `NO_COLOR` still wins over `auto`.
|
|
183
201
|
`always` still stays plain on a Windows console that cannot do ANSI.
|
|
184
202
|
|
|
185
203
|
Extra row fields: `list` rows carry `at`, `mechanism`, `companions`; `cost` rows
|
|
@@ -224,57 +242,186 @@ A colon addresses nesting: `demo:batch` is `commands/demo/batch.md`.
|
|
|
224
242
|
## Interactive picker
|
|
225
243
|
|
|
226
244
|
```sh
|
|
227
|
-
agent-toggle ui
|
|
245
|
+
agent-toggle ui # alias: agent-toggle pick
|
|
246
|
+
agent-toggle # same, on a terminal; elsewhere prints help and exits 2
|
|
228
247
|
```
|
|
229
248
|
|
|
230
249
|
```
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
250
|
+
agent-toggle v0.5.1 5 resources · ~6.3k tok live · 1 staged (+300 tok)
|
|
251
|
+
All 5 │ claude 4 │ codex 2
|
|
252
|
+
🔍 Type to search (name, path, fuzzy) type: All sort: name
|
|
253
|
+
Skills 3 ─────────────────────────────────────────────────────────────│ beta
|
|
254
|
+
● alpha claude 1.2k █▎ │
|
|
255
|
+
› ● + beta claude (300) ▎ │ harness claude
|
|
256
|
+
● zeta claude 5.0k █████ │ type skill
|
|
257
|
+
Agents 1 ─────────────────────────────────────────────────────────────│ state ○ parked
|
|
258
|
+
● gamma claude 50 ▏ +shared │ staged → live
|
|
259
|
+
Commands 1 ───────────────────────────────────────────────────────────│ path ~/.claude/skills-disabled/beta
|
|
260
|
+
● delta codex 10 ▏ │ cost 0 now; ~300 tok if restored
|
|
261
|
+
│ since 2026-09-19 10:00:00
|
|
262
|
+
5 of 5 shown · 2/5
|
|
263
|
+
Space toggle Enter apply Esc cancel ? help / search ←→ harness t type s sort p profile a all
|
|
239
264
|
```
|
|
240
265
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
266
|
+
What is on screen:
|
|
267
|
+
|
|
268
|
+
- **Title bar**: version and a summary (resources, live tokens, staged changes and their token effect).
|
|
269
|
+
- **Harness tab bar**: `All` plus each enabled harness, with counts. Harnesses switched off in
|
|
270
|
+
the [settings](#settings--config-menu) are hidden.
|
|
271
|
+
- **Rows grouped by type** (Skills, Agents, Commands, ...) under a heading with a count.
|
|
272
|
+
`●` is live, `○` parked (`*` / `o` in ASCII); a `+` / `-` before the name marks a staged change,
|
|
273
|
+
and `+shared` marks a directory another harness also reads.
|
|
274
|
+
- **Cost column**: estimated startup tokens (chars / 4, about +-25 %) with a colored bar. A parked
|
|
275
|
+
row shows `(N)` in brackets, what restoring it would load. Plugins appear as rows too (via
|
|
276
|
+
`claude plugin list --json`; skipped under `ui --dry-run`, which never shells out).
|
|
277
|
+
- **Detail pane** at 100 columns or wider: the file's frontmatter `description` (skills,
|
|
278
|
+
agents, commands, rules), then harness, type, state, staged, path, cost, since,
|
|
279
|
+
mechanism, and what it is shared with.
|
|
280
|
+
- **Search bar** (🔍; plain `/` on terminals that cannot draw emoji: the Linux console, the legacy
|
|
281
|
+
Windows console, non-UTF-8 locales) under the tabs, always visible.
|
|
282
|
+
- **Per-harness colors** on the harness column, matching `ai-accounts list` (claude orange on
|
|
283
|
+
256-color terminals, codex cyan, agy blue, grok yellow, vibe green, copilot red, opencode magenta).
|
|
284
|
+
- **Key-chip footer** and a `?` help overlay. A spinner shows on stderr while the list loads
|
|
285
|
+
(only on a TTY; off with `NO_COLOR`). The mouse wheel scrolls (xterm alternate-scroll mode).
|
|
245
286
|
|
|
246
287
|
| key | action |
|
|
247
288
|
|---|---|
|
|
248
|
-
| `
|
|
249
|
-
| `
|
|
289
|
+
| `Space` | toggle the highlighted row (live / parked) and stay on it (while filtering, `Space` types a space) |
|
|
290
|
+
| `Tab` | toggle the highlighted row and advance to the next |
|
|
291
|
+
| `Enter` | apply every staged change (with `--dry-run`: show the plan) |
|
|
292
|
+
| `Esc` / `Ctrl-C` | cancel; nothing is applied |
|
|
293
|
+
| `↑` `↓` `PgUp` `PgDn` `Home` `End`, `Ctrl-P` / `Ctrl-N` | move |
|
|
294
|
+
| `/` | start a search; any other non-command letter starts one too. Terms are ANDed, case-insensitive, and match the harness/type/name and the path; when nothing matches, letters-in-order (fuzzy) is tried: `ctxmd` finds `context-md`, and the bar says `≈ fuzzy match` |
|
|
295
|
+
| `Backspace` / `Ctrl-U` | delete one character / clear the filter |
|
|
296
|
+
| `←` `→` | switch harness tab (also while typing a filter); `0` = All, `1`-`9` = that tab, `h` = next tab |
|
|
250
297
|
| `t` | cycle the type filter |
|
|
298
|
+
| `s` | cycle sort: name, cost (biggest first); applies within each type group |
|
|
299
|
+
| `p` | profiles: stage a saved one, or save the live state (see below) |
|
|
251
300
|
| `?` | show the key list |
|
|
252
|
-
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
| `Enter` | apply every staged change (with `--dry-run`: show the plan) |
|
|
258
|
-
| `Esc` / `Ctrl-C` | cancel — nothing is applied |
|
|
301
|
+
| `a` / `Ctrl-A` | toggle every visible row |
|
|
302
|
+
|
|
303
|
+
The command keys (`t`, `s`, `p`, `h`, `a`, `0`-`9`, `?`) act only while no filter is active.
|
|
304
|
+
Press `/` first to type a filter that begins with one of them; once the filter is non-empty,
|
|
305
|
+
every letter just types.
|
|
259
306
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
307
|
+
The start view (sort, harness tab, type filter) comes from the `picker_sort`, `picker_harness`
|
|
308
|
+
and `picker_type` [settings](#settings--config-menu). A profile skips harnesses that are hidden
|
|
309
|
+
and counts those items as `hidden by settings`; `ui --harness <name>` shows that harness even
|
|
310
|
+
when it is switched off.
|
|
263
311
|
|
|
264
|
-
|
|
265
|
-
|
|
312
|
+
`p` opens a prompt over the list of saved profiles: type a number or name (or
|
|
313
|
+
`apply <name>`) and Enter to **stage** that profile's changes (only the items it
|
|
314
|
+
mentions; ones this machine lacks are skipped), then Enter in the picker applies
|
|
315
|
+
them like any other change, so `ui --dry-run` previews a profile and a stray
|
|
316
|
+
`p` changes nothing. `save <name>` writes the live state (not your staged changes) as
|
|
317
|
+
a profile, with the same name rules and project scope as `profile save`; it is
|
|
318
|
+
off under `--dry-run`. Esc closes the prompt.
|
|
266
319
|
|
|
267
320
|
Nothing happens while the picker is open. Changes are staged, the screen is
|
|
268
|
-
torn down, and only then do the real operations run
|
|
321
|
+
torn down, and only then do the real operations run, so their output (which
|
|
269
322
|
companion files moved, which were kept because they are shared) is readable
|
|
270
323
|
instead of fighting curses for the terminal.
|
|
271
324
|
|
|
272
325
|
Built on stdlib `curses`, so there is nothing to install on macOS and Linux
|
|
273
326
|
(on Windows, `pip install "agent-toggle[windows]"` pulls `windows-curses`).
|
|
274
327
|
Without curses, `ui` falls back to a numbered menu with the same staging and the
|
|
275
|
-
same result
|
|
276
|
-
|
|
277
|
-
|
|
328
|
+
same result. It is grouped by type, with the same glyphs and color: type row
|
|
329
|
+
numbers (`1 3 5-7`) to tick or untick, `/text` to filter (`/` alone clears it),
|
|
330
|
+
`s` / `h` / `t` to sort and cycle the harness and type filters, `p` to list profiles,
|
|
331
|
+
`p <number|name>` to stage one and `p save <name>` to save the live state, `a` to
|
|
332
|
+
apply, `q` (or end of input) to cancel.
|
|
333
|
+
|
|
334
|
+
The chrome (title, tabs, footer, help, detail labels) is translated when `language` is
|
|
335
|
+
`zh-TW`; item names and paths are never translated.
|
|
336
|
+
|
|
337
|
+
## Settings & config menu
|
|
338
|
+
|
|
339
|
+
```sh
|
|
340
|
+
agent-toggle config # or: agent-toggle --config
|
|
341
|
+
agent-toggle config --json # every setting with its value and source, plus the package version; the token is masked
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
`config` opens the settings menu: curses on a terminal, a numbered list otherwise. The title
|
|
345
|
+
shows the package version. Each change is saved the moment you make it. On a numbered list,
|
|
346
|
+
end of input, `q` or an empty line exits `0`
|
|
347
|
+
(safe in CI; note it reads piped digits, so an open stdin pipe waits).
|
|
348
|
+
|
|
349
|
+
| group | rows |
|
|
350
|
+
|---|---|
|
|
351
|
+
| General | Check for updates, Color, Language, Default harness |
|
|
352
|
+
| Harnesses | one On/Off per harness, with `found ~/.x` or `not on this machine` |
|
|
353
|
+
| Picker | default sort, harness filter, type filter |
|
|
354
|
+
| Notifications | Telegram bot token (masked), Telegram chat ID |
|
|
355
|
+
| Tools | Health check (`doctor`; then asks y/n per fix it can run), Install shims, Undo last change (asks y/n), Send test message, Sync CI secrets (asks y/n); their output shows in an overlay |
|
|
356
|
+
|
|
357
|
+
Keys: `↑` `↓` move (wraps, skips headings), `←` `→` cycle a value, `Enter` / `Space` change or run
|
|
358
|
+
the row, `r` reset the row, `R` reset everything (asks y/n), `q` / `Esc` / `Ctrl-C` quit. In an
|
|
359
|
+
inline text field `Enter` commits, `Esc` cancels and `-` then `Enter` clears. A dim `env` tag
|
|
360
|
+
marks a row whose value is overridden by an environment variable. The Language row switches the
|
|
361
|
+
UI live.
|
|
362
|
+
|
|
363
|
+
Settings live in `~/.agent-toggle/config.json` (mode `0600`, written atomically; keys the
|
|
364
|
+
tool does not know are kept):
|
|
365
|
+
|
|
366
|
+
| key | values | default | env override |
|
|
367
|
+
|---|---|---|---|
|
|
368
|
+
| `update_check` | `true` / `false` | `true` | `AGENT_TOGGLE_UPDATE_CHECK` |
|
|
369
|
+
| `color` | `auto` / `always` / `never` | `auto` | `AGENT_TOGGLE_COLOR` |
|
|
370
|
+
| `language` | `en` / `zh-TW` | `en` | `AGENT_TOGGLE_LANG` |
|
|
371
|
+
| `default_harness` | a harness name | `claude` | `AGENT_TOGGLE_DEFAULT_HARNESS` |
|
|
372
|
+
| `harness.<name>` | `true` / `false`, for `claude` `codex` `grok` `opencode` `openclaw` `copilot` `vibe` `devin` `agy` | `true` | |
|
|
373
|
+
| `picker_sort` | `name` / `cost` | `name` | |
|
|
374
|
+
| `picker_harness` | `all` or a harness name | `all` | |
|
|
375
|
+
| `picker_type` | `all` or a type | `all` | |
|
|
376
|
+
| `telegram_chat_id` | a number, `-100...` or `@channel` | unset | `TG_CHAT_ID` |
|
|
377
|
+
|
|
378
|
+
The bot token is not in this file: it is in the OS keystore through telegram-kit
|
|
379
|
+
(`TG_BOT_TOKEN` overrides it). An environment variable always beats the file; an
|
|
380
|
+
invalid value in either is ignored with one warning on stderr.
|
|
381
|
+
|
|
382
|
+
- `harness.<name>` off hides that harness from `ui`, `list`, `status` and `cost` (`list`, `status` and
|
|
383
|
+
`cost` print a dim `N hidden by settings` note, and `--json` carries it in `warnings`; an item shared with a harness that is still
|
|
384
|
+
on stays listed) and `install-shims` skips it; an explicit
|
|
385
|
+
`--harness <name>` still reaches it, `ui --harness <name>` included.
|
|
386
|
+
- `default_harness` is what `disable` / `enable` act on without `--harness`, even when that
|
|
387
|
+
harness is switched off (with one warning on stderr);
|
|
388
|
+
`disable` / `enable --project` without `--harness` still default to `claude`.
|
|
389
|
+
- `language` translates the config menu, help, update prompt and picker chrome; command output stays English.
|
|
390
|
+
- Bare `config` works without the `[telegram]` extra; `config test` and `config sync-ci` are
|
|
391
|
+
unchanged and need it (exit `4` without it).
|
|
392
|
+
|
|
393
|
+
## Update check
|
|
394
|
+
|
|
395
|
+
On every invocation (unless disabled) agent-toggle checks PyPI for a newer release. It starts
|
|
396
|
+
before the command and is offered after it, on every exit path; it overlaps the command and waits at most 0.8 s afterwards.
|
|
397
|
+
|
|
398
|
+
- **On a terminal** (stdin and stderr are TTYs, no `--json`): a panel on stderr, "agent-toggle X
|
|
399
|
+
is available (you have Y)", with `Update now`, `Skip` and `Skip until next version`, a release
|
|
400
|
+
notes link, and `↑` `↓` `Enter` `q`. `Update now` runs `uv tool upgrade agent-toggle`; if that
|
|
401
|
+
fails you get a yellow warning with the command to run yourself.
|
|
402
|
+
- **Off a terminal**: two stderr lines, `agent-toggle X is available (you have Y)` and
|
|
403
|
+
` uv tool upgrade agent-toggle`.
|
|
404
|
+
- It never changes the exit code or stdout, so `--json` output stays one document.
|
|
405
|
+
|
|
406
|
+
It is one `GET https://pypi.org/pypi/agent-toggle/json` on a background thread with a 0.8 s
|
|
407
|
+
timeout, cached for 10 minutes in `~/.agent-toggle/update-check.json`. Nothing is sent beyond a
|
|
408
|
+
normal HTTP request with the User-Agent `agent-toggle-update-check`. See `SECURITY.md`
|
|
409
|
+
for the hardening. To turn it off, set `AGENT_TOGGLE_UPDATE_CHECK=0` or the `update_check` setting
|
|
410
|
+
to off (the settings menu's "Check for updates").
|
|
411
|
+
|
|
412
|
+
## Help
|
|
413
|
+
|
|
414
|
+
```sh
|
|
415
|
+
agent-toggle help # grouped overview
|
|
416
|
+
agent-toggle help config # one command; same as: --help config, config --help
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Help is grouped as Toggle (`ui`, `disable`, `enable`, `undo`, `profile`), Inspect (`status`,
|
|
420
|
+
`list`, `cost`, `doctor`) and Setup (`config`, `install-shims`, `migrate`), with the global
|
|
421
|
+
options, examples and exit codes. `help <command>` shows that command's usage, arguments,
|
|
422
|
+
options and examples; `help help` is the overview, `help version` shows how to print the version,
|
|
423
|
+
and an unknown command exits `2`. It honours `--color` and `NO_COLOR`, and is
|
|
424
|
+
translated when `language` is `zh-TW`.
|
|
278
425
|
|
|
279
426
|
## What each harness supports
|
|
280
427
|
|
|
@@ -330,16 +477,19 @@ rather than guessing.
|
|
|
330
477
|
### Shared directories
|
|
331
478
|
|
|
332
479
|
OpenCode may read skills from another harness's directory through
|
|
333
|
-
`opencode.json` → `skills.paths` (absolute,
|
|
334
|
-
|
|
335
|
-
|
|
480
|
+
`opencode.json` → `skills.paths` (absolute, `~`, `$HOME/...`
|
|
481
|
+
and `${HOME}/...` entries; read from `opencode.json`, else `opencode.jsonc`;
|
|
482
|
+
relative entries are skipped, since OpenCode resolves them against the session
|
|
483
|
+
directory). OpenCode also always scans `~/.claude/skills` and `~/.agents/skills`,
|
|
484
|
+
so claude's skills count as shared with it. Such a directory is **one** item, filed under
|
|
336
485
|
its owner (the harness whose home really holds it): it is
|
|
337
486
|
parked once, tracked once, and every row reports `shared_with`, the other
|
|
338
487
|
harnesses it also affects. `status` prints `shared dir with: ...`.
|
|
339
488
|
|
|
340
489
|
If the live directory carries `.synced-from-*` markers, a sync job may
|
|
341
|
-
re-create what you parked; `status`
|
|
342
|
-
instead. The warning is printed once per
|
|
490
|
+
re-create what you parked; `status` and `disable` warn about it. Park in the
|
|
491
|
+
source harness instead. The warning is printed once per real directory, naming
|
|
492
|
+
every harness that views it.
|
|
343
493
|
|
|
344
494
|
## Companion files
|
|
345
495
|
|
|
@@ -461,8 +611,10 @@ bulk operations with `--dry-run`.
|
|
|
461
611
|
Claude layout only: `--harness codex --project ...` exits `4`, as does a
|
|
462
612
|
missing directory or one with neither `.claude/` nor `.mcp.json`. `$HOME`, its
|
|
463
613
|
ancestors, the tool's own state dir and the harness homes are refused (exit
|
|
464
|
-
`2`) -- that is user scope. `list
|
|
465
|
-
`
|
|
614
|
+
`2`) -- that is user scope. `list`, `enable --all`, `cost` and `ui` run the same
|
|
615
|
+
checks. `cost --project` prices that project's items only (no plugins), and
|
|
616
|
+
`ui --project` stages and applies in project scope (its `p` key saves and applies
|
|
617
|
+
project profiles).
|
|
466
618
|
|
|
467
619
|
```sh
|
|
468
620
|
agent-toggle disable skill demo-skill --project .
|
|
@@ -485,18 +637,21 @@ agent-toggle enable --all --project .
|
|
|
485
637
|
Restore with that command, or `git checkout`; do not commit the deletion if
|
|
486
638
|
the repo is shared.
|
|
487
639
|
- `.mcp.json` is edited directly (no `claude` CLI) and must be **strict JSON**:
|
|
488
|
-
a BOM, comments or trailing commas are refused. `disable`
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
640
|
+
a BOM, comments or trailing commas are refused. `disable` cuts only that
|
|
641
|
+
server's entry, leaving every other byte as it was, and saves a backup at
|
|
642
|
+
`mcp-backups/<sha8>__claude__<name>.json` (mode `0600`) holding only that entry
|
|
643
|
+
-- its own headers, never another server's. `enable` puts the entry's bytes
|
|
644
|
+
back into the current file (an unchanged file comes back byte for byte; after
|
|
645
|
+
other edits it goes after its old neighbour, else at the end, indented like the
|
|
646
|
+
file) and checks that nothing else changed.
|
|
647
|
+
- A move across filesystems copies into a temp dir beside the target, renames it
|
|
648
|
+
into place, then deletes the source, so a killed run leaves either the source
|
|
649
|
+
intact or the target complete, and the next run settles it (see "Where state
|
|
650
|
+
lives"). `enable` removes the emptied `parked/<sha8>/*-disabled` and
|
|
651
|
+
`parked/<sha8>` dirs; a dir that still holds anything is kept.
|
|
496
652
|
- `status` prints one `project <dir>` line per project holding parked items.
|
|
497
|
-
A project with only `.mcp.json`
|
|
498
|
-
`profile save --project
|
|
499
|
-
`.claude/`).
|
|
653
|
+
A project with only `.mcp.json` has its live servers listed too in
|
|
654
|
+
`profile save --project`, next to its parked ones.
|
|
500
655
|
|
|
501
656
|
## Doctor
|
|
502
657
|
|
|
@@ -504,31 +659,56 @@ agent-toggle enable --all --project .
|
|
|
504
659
|
agent-toggle doctor [--harness H] [--json]
|
|
505
660
|
```
|
|
506
661
|
|
|
507
|
-
|
|
662
|
+
The check is read-only: no lock, no state write-back, no `claude` CLI call. For each
|
|
508
663
|
installed harness it compares the live layout with the table row (expected
|
|
509
664
|
dirs and config keys), then cross-checks `state.json` against disk (parked
|
|
510
665
|
item present, origin dir present, backup present, project dir present, entry
|
|
511
|
-
passes the same tamper checks `enable` runs,
|
|
512
|
-
`0700`). Rows (`action: doctor`) carry a status:
|
|
666
|
+
passes the same tamper checks `enable` runs, companion files present and not also
|
|
667
|
+
live, modes no looser than `0600` / `0700`). Rows (`action: doctor`) carry a status:
|
|
513
668
|
|
|
514
669
|
| status | meaning |
|
|
515
670
|
|---|---|
|
|
516
671
|
| `ok` | matches |
|
|
517
672
|
| `absent` | a dir, config file or key the row expects is not there (an MCP file never created, a missing `mcpServers` key) -- informational, exit `0` |
|
|
518
673
|
| `note` | worth knowing: shared dir, orphan backup, JSONC `openclaw.json` / `opencode.json`, a `--harness` that is not installed |
|
|
519
|
-
| `unverified` | could
|
|
520
|
-
| `warn` | loose file modes; a parked item with no state entry; a leftover `parked/<sha8>` dir that still holds files (an empty one
|
|
521
|
-
| `error` | needs fixing: a config that exists but is unparseable or unsupported (`layout changed`), a state entry whose files are gone or fail the tamper checks, a flag re-enabled outside the tool |
|
|
674
|
+
| `unverified` | no version could be read, or the row has nothing to check |
|
|
675
|
+
| `warn` | loose file modes; a parked item or companion file with no state entry; a leftover `parked/<sha8>` dir that still holds files (an empty one is ignored); an op a killed run left in flight that the next change settles (`pending: done` / `undone`) |
|
|
676
|
+
| `error` | needs fixing: a config that exists but is unparseable or unsupported (`layout changed`), a state entry whose files (companions included) are gone or fail the tamper checks, a companion both live and parked, a flag re-enabled outside the tool, an op a killed run left in flight that needs you (`pending: stuck`, with the exact fix) |
|
|
522
677
|
|
|
523
678
|
Only `error` makes the exit code `1`; each problem row names the command that
|
|
524
679
|
fixes it. `--harness X` for a harness that is not installed is a `note` (exit
|
|
525
|
-
`0`).
|
|
680
|
+
`0`).
|
|
526
681
|
|
|
527
682
|
A harness item parked with no state entry also carries `orphan`, and its fix
|
|
528
683
|
follows from it: `identical` (the live copy has the same content: delete the
|
|
529
684
|
parked copy), `differs` (a different live copy exists: compare, keep one), or
|
|
530
685
|
`parked-only` (move it back, then `disable` it so the state records it).
|
|
531
686
|
|
|
687
|
+
### Fixing
|
|
688
|
+
|
|
689
|
+
`install-shims` (and so `./install.sh`) runs the same check silently after
|
|
690
|
+
writing the shims and asks only about these fixable problems, each shown first.
|
|
691
|
+
|
|
692
|
+
On a terminal (stdin and stdout both a TTY, no `--json`) doctor then asks
|
|
693
|
+
`(y/n)` for each problem it can fix without a judgment call, and runs each yes
|
|
694
|
+
under the run lock; anything else keeps its `fix:` hint for you. A fixed row's
|
|
695
|
+
status becomes `fixed` and no longer counts toward the exit code; a failed fix
|
|
696
|
+
adds an `error` row. Piped, `--json`, or run by an agent through a shim, doctor
|
|
697
|
+
stays read-only.
|
|
698
|
+
|
|
699
|
+
| problem | fix it offers |
|
|
700
|
+
|---|---|
|
|
701
|
+
| loose mode on the state dir, `state.json` or a backup | `chmod 700` / `chmod 600` |
|
|
702
|
+
| backup with no state entry, server configured again in its harness | delete the backup (not offered while the server is missing, nor for project backups) |
|
|
703
|
+
| flag re-enabled outside the tool | `enable` the item, which clears the stale entry |
|
|
704
|
+
| origin dir gone | recreate it, then `enable` the item |
|
|
705
|
+
| op a killed run left in flight (`pending: done` / `undone`) | settle it now, as the next change would |
|
|
706
|
+
| orphan parked item, `identical` | delete the parked copy |
|
|
707
|
+
| orphan parked item, `parked-only` | move it back (restores it) |
|
|
708
|
+
|
|
709
|
+
Not offered: `differs` orphans, missing parked items or backups, a gone project
|
|
710
|
+
dir, tamper refusals, `pending: stuck`, companion conflicts, unparseable configs.
|
|
711
|
+
|
|
532
712
|
## Assumed formats
|
|
533
713
|
|
|
534
714
|
Two config shapes came from the design survey (`docs/DESIGN.md` §4 / §11). Both
|
|
@@ -540,14 +720,16 @@ were since seen on one real install each (openclaw 2026.7.1-2, opencode 2.0.22;
|
|
|
540
720
|
- `opencode.json`: `mcp.<name>.enabled`
|
|
541
721
|
|
|
542
722
|
The edit changes one boolean token and nothing else, is verified after writing
|
|
543
|
-
and rolled back on any mismatch (bytes and file mode).
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
refused
|
|
723
|
+
and rolled back on any mismatch (bytes and file mode). JSONC (`//` and `/* */`
|
|
724
|
+
comments, trailing commas) is edited the same way: only the flag token changes,
|
|
725
|
+
comments and commas are kept. JSON5 (unquoted keys, single quotes, hex) and files
|
|
726
|
+
that repeat a key are **refused**, never rewritten; a leading BOM is kept as is; a
|
|
727
|
+
missing key is refused, never invented. An openclaw skill
|
|
547
728
|
uses the flag only when `skills.entries.<name>` already exists, otherwise its
|
|
548
|
-
directory is moved.
|
|
549
|
-
|
|
550
|
-
|
|
729
|
+
directory is moved. The state entry (with the flag's previous value) is saved
|
|
730
|
+
before the flag is written, so a run killed in between is settled by the next
|
|
731
|
+
run, never guessed (see "Where state lives"). Please report a real install that
|
|
732
|
+
differs.
|
|
551
733
|
|
|
552
734
|
## Safety checks
|
|
553
735
|
|
|
@@ -559,8 +741,9 @@ back by hand. Please report a real install that differs.
|
|
|
559
741
|
invalid codex `config.toml` makes an MCP edit fail and roll back instead of
|
|
560
742
|
being rewritten. A codex `config.toml` edit also fails (and is left as the other
|
|
561
743
|
tool wrote it) if the file changed between read and write, and CRLF files keep their
|
|
562
|
-
line endings. On Python 3.10 (no `tomllib`) the
|
|
563
|
-
|
|
744
|
+
line endings. On Python 3.10 (no `tomllib`) the edit is parse-checked by a stdlib structural
|
|
745
|
+
validator (`agent_toggle/toml_check.py`, differentially tested against `tomllib`),
|
|
746
|
+
on top of the textual check that only the one block changed.
|
|
564
747
|
- Profiles and project dirs are validated like command-line input.
|
|
565
748
|
|
|
566
749
|
## Where state lives
|
|
@@ -571,13 +754,29 @@ bookkeeping.
|
|
|
571
754
|
|
|
572
755
|
| file | contents |
|
|
573
756
|
|---|---|
|
|
574
|
-
| `state.json` | current disabled list (schema v3; atomic write, mode `0600`) |
|
|
575
|
-
| `lock` | held by `disable` / `enable` / `enable --all` / `undo` / `profile apply` / `migrate` / `ui` for the whole batch; a second run waits 5 s then exits `3` (stale after 10 min *and* its PID is gone; a live batch refreshes it per item) |
|
|
757
|
+
| `state.json` | current disabled list (schema v3; atomic write, mode `0600`), saved before each flag write or dir move with the op in flight under an optional `pending` key, and after each MCP / plugin item |
|
|
758
|
+
| `lock` | held by `disable` / `enable` / `enable --all` / `undo` / `profile apply` / `migrate` / `ui` for the whole batch; a second run waits 5 s then exits `3` (stale after 10 min *and* its PID is gone; a live batch refreshes it per item; the error says when its PID is gone, i.e. a killed run left it) |
|
|
576
759
|
| `log.jsonl` | one line per operation (mode `0600`), see below |
|
|
577
760
|
| `mcp-backups/` | `<harness>__<server>.json`, or `<sha8>__<harness>__<server>.json` for a project `.mcp.json` (mode `0600` -- may hold auth headers) |
|
|
578
761
|
| `companions/` | parked exclusive helper files |
|
|
579
762
|
| `parked/<sha8>/` | items parked by `--project` (`<sha8>` = first 8 hex of the SHA-1 of the resolved project dir) |
|
|
580
763
|
| `profiles/` | `<name>.json` profiles (dir `0700`, files `0600`) |
|
|
764
|
+
| `config.json` | [settings](#settings--config-menu) and the Telegram chat id (mode `0600`, atomic write, unknown keys kept) |
|
|
765
|
+
| `update-check.json` | the [update check](#update-check)'s 10-minute cache (mode `0600`, atomic write) |
|
|
766
|
+
|
|
767
|
+
A killed run loses at most the one item in flight. If that was a flag write or a
|
|
768
|
+
dir move (with its companions), its `pending` record (the full entry, a flag's
|
|
769
|
+
previous value included) lets the next `disable` / `enable` / `enable --all` /
|
|
770
|
+
`undo` / ... finish it (it reached disk: recorded) or drop it (it did not), with
|
|
771
|
+
a warning and a `recovered` log row (which `undo` does not reverse). `status` and
|
|
772
|
+
`doctor` report it, with `agent-toggle enable ...` when the item ends up
|
|
773
|
+
disabled. The one case left to you is a cross-filesystem move killed between its
|
|
774
|
+
two renames: both copies are complete, and the report names the `diff -r` to
|
|
775
|
+
check and the `rm -rf` that keeps either one. MCP and plugin items are saved
|
|
776
|
+
per item (when the next one starts), without a `pending` record (a project `.mcp.json`
|
|
777
|
+
edit has one): a kill inside that window
|
|
778
|
+
leaves the change unrecorded (an MCP server's backup stays in `mcp-backups/`).
|
|
779
|
+
A killed run also leaves its `lock`; the next run's error says so.
|
|
581
780
|
|
|
582
781
|
Each `log.jsonl` row is `{ts, harness, type, name, action, result, batch,
|
|
583
782
|
project, scope, detail}`. `batch` is one id per run (what `undo` reverses);
|
|
@@ -599,7 +798,9 @@ path exists as a *file*, so the `is_dir()` check has to come **before** the
|
|
|
599
798
|
`mkdir` or it is unreachable.
|
|
600
799
|
|
|
601
800
|
**2. Park dirs that are not gitignored get a warning.** Without it, every
|
|
602
|
-
disable leaves dozens of deletion lines in `git status`.
|
|
801
|
+
disable leaves dozens of deletion lines in `git status`. The warning is shown once
|
|
802
|
+
per park dir, and only for a dir inside a git work tree (elsewhere `git status`
|
|
803
|
+
cannot be dirtied and the `.gitignore` fix would not apply).
|
|
603
804
|
|
|
604
805
|
## Paths are resolved before comparison
|
|
605
806
|
|
|
@@ -632,19 +833,21 @@ runs. The message names the repository, branch, 7-character commit and a link to
|
|
|
632
833
|
Set it up once, with the `telegram` extra installed (see [Install](#install)):
|
|
633
834
|
|
|
634
835
|
```sh
|
|
635
|
-
agent-toggle config #
|
|
836
|
+
agent-toggle config # settings menu: Notifications has the bot token (hidden) and chat id
|
|
636
837
|
agent-toggle config test # send one test message
|
|
637
838
|
agent-toggle config sync-ci # set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID on the repo
|
|
638
839
|
```
|
|
639
840
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
is
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
841
|
+
In the [settings menu](#settings--config-menu) an inline field commits on `Enter`, cancels on
|
|
842
|
+
`Esc`, and clears on `-` then `Enter`; the Tools group also has Send test message and Sync CI
|
|
843
|
+
secrets (the same as `config test` / `config sync-ci`, and they need the extra). The bot token
|
|
844
|
+
is kept only in the OS credential store (macOS Keychain, Linux Secret Service, Windows DPAPI)
|
|
845
|
+
through telegram-kit, never in a file or on a command line, and is shown masked. With no
|
|
846
|
+
credential store it refuses to store the token; set `TG_BOT_TOKEN` in the environment instead
|
|
847
|
+
(`TG_CHAT_ID` likewise for the chat id). The chat id (`telegram_chat_id`) is ordinary
|
|
848
|
+
configuration in `~/.agent-toggle/config.json`: a number, `-100...` for a group, or an
|
|
849
|
+
`@channel`. `config sync-ci` needs the GitHub CLI (`gh`) signed in; it passes both values on
|
|
850
|
+
stdin, and `--repo OWNER/REPO` / `--dry-run` work as elsewhere.
|
|
648
851
|
|
|
649
852
|
To skip the tool, set the secrets by hand (each command prompts for the value):
|
|
650
853
|
|