@iinm/plain-agent 1.7.19 → 1.7.21

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.
package/README.md CHANGED
@@ -1,10 +1,6 @@
1
- <p align="center">
2
- <img src="https://pub-0bb49aa929f242d49c89ed8c297932b5.r2.dev/plain-agent/plain-agent-logo.png" alt="plain-agent logo" width="320">
3
- </p>
4
-
5
1
  # Plain Agent
6
2
 
7
- A lightweight CLI-based coding agent with zero framework dependencies.
3
+ A lightweight CLI-based coding agent.
8
4
 
9
5
  ## Why Plain Agent?
10
6
 
@@ -23,6 +19,7 @@ A lightweight CLI-based coding agent with zero framework dependencies.
23
19
 
24
20
  ## Limitations
25
21
 
22
+ - **CLI only** — Plain Agent does not provide a terminal UI.
26
23
  - **Sequential subagent execution** — Subagents run one at a time rather than
27
24
  in parallel. The trade-off is full visibility: every step is streamed to
28
25
  your terminal so you can follow exactly what each subagent is doing.
@@ -31,7 +28,7 @@ A lightweight CLI-based coding agent with zero framework dependencies.
31
28
 
32
29
  - Node.js 22 or later
33
30
  - LLM provider credentials
34
- - bash / docker for sandboxed execution
31
+ - Bash / Docker for sandboxed execution
35
32
  - [ripgrep](https://github.com/burntsushi/ripgrep)
36
33
  - [fd](https://github.com/sharkdp/fd)
37
34
 
@@ -52,8 +49,8 @@ Create the configuration.
52
49
  ```js
53
50
  // ~/.config/plain-agent/config.local.json
54
51
  {
55
- "model": "gpt-5.4+thinking-high",
56
- // "model": "claude-sonnet-4-6+thinking-high",
52
+ "model": "claude-sonnet-4-6+thinking-high",
53
+ // "model": "gpt-5.5+thinking-high",
57
54
 
58
55
  // Configure the providers you want to use
59
56
  "platforms": [
@@ -83,15 +80,11 @@ Create the configuration.
83
80
  "provider": "gemini",
84
81
  "apiKey": "<GEMINI_API_KEY>",
85
82
  "model": "gemini-3-flash-preview"
86
- // Optional
87
- // "baseURL": "<proxy_url>"
88
83
 
89
84
  // Or use Vertex AI (Requires gcloud CLI to get authentication token)
90
85
  // "provider": "gemini-vertex-ai",
91
86
  // "baseURL": "https://aiplatform.googleapis.com/v1beta1/projects/<project_id>/locations/<location>",
92
87
  // "model": "gemini-3-flash-preview"
93
- // Optional:
94
- // "account": "<service_account_email>"
95
88
  },
96
89
 
97
90
  // askURL: Answers questions based on provided URL content.
@@ -100,15 +93,8 @@ Create the configuration.
100
93
  "provider": "gemini",
101
94
  "apiKey": "<GEMINI_API_KEY>"
102
95
  "model": "gemini-3-flash-preview"
103
- // Optional
104
- // "baseURL": "<proxy_url>"
105
96
 
106
97
  // Or use Vertex AI (Requires gcloud CLI to get authentication token)
107
- // "provider": "gemini-vertex-ai",
108
- // "baseURL": "https://aiplatform.googleapis.com/v1beta1/projects/<project_id>/locations/<location>",
109
- // "model": "gemini-3-flash-preview"
110
- // Optional:
111
- // "account": "<service_account_email>"
112
98
  }
113
99
  },
114
100
 
@@ -166,6 +152,7 @@ Create the configuration.
166
152
  ```
167
153
 
168
154
  ```js
155
+ // OpenAI-compatible provider (Ollama) example with a custom model
169
156
  {
170
157
  "platforms": [
171
158
  {
@@ -268,31 +255,26 @@ Create the configuration.
268
255
  ```
269
256
  </details>
270
257
 
271
-
272
-
273
258
  Run the agent.
274
259
 
275
260
  ```sh
276
261
  plain
277
-
278
- # Or
279
- plain -m <model+variant>
280
262
  ```
281
263
 
282
- (Optional) Set up a sandbox for your project with the `sandbox-configurator` agent.
283
-
284
264
  ```
285
- /agents:sandbox-configurator Set up a sandbox for this project
265
+ plain -m <model+variant>
286
266
  ```
287
267
 
288
- After the agent finishes, run the generated setup script once to build the sandbox image and install dependencies.
268
+ Press **Ctrl-C** to pause auto-approve. The agent will finish the current tool call, then return to the prompt.
289
269
 
290
- ```sh
291
- ./.plain-agent/setup.sh
270
+ Display the help message.
271
+
272
+ ```
273
+ /help
292
274
  ```
293
275
 
294
276
  Run in batch mode (non-interactive).
295
- In batch mode, config files are not loaded automatically. Only the files specified with `--config` are loaded.
277
+ In batch mode, config files are not loaded automatically. Only the files specified with `-c` are loaded.
296
278
 
297
279
  ```sh
298
280
  plain batch \
@@ -301,66 +283,48 @@ plain batch \
301
283
  "Add tests for ..."
302
284
  ```
303
285
 
304
- Display the help message.
305
-
306
- ```
307
- /help
308
- ```
309
-
310
- Show aggregated token cost per day across sessions.
311
- Each finished session appends a record to `~/.local/share/plain-agent/usage.jsonl`,
312
- and `plain cost` reads that log. The period defaults to the first day of the
313
- current month through today; override it with `--from` / `--to`. Multiple
314
- currencies (e.g., USD and JPY) are aggregated separately.
286
+ Show daily token costs across sessions. `plain cost` reads
287
+ `~/.local/share/plain-agent/usage.jsonl`; use `--from` / `--to` to set the
288
+ period. Currencies are shown separately.
315
289
 
316
290
  ```sh
317
291
  plain cost
318
- plain cost --from 2026-04-01 --to 2026-04-30
319
292
  ```
320
293
 
321
- Interrupt the agent while it's running:
322
-
323
- Press **Ctrl-C** to pause auto-approve. The agent will finish the current tool call, then return to the prompt.
294
+ ```
295
+ plain cost --from 2026-04-01 --to 2026-04-30
296
+ ```
324
297
 
325
- ## Available Tools
298
+ (Optional) Configure plain-agent for your project.
326
299
 
327
- The agent can use the following tools to assist with tasks:
300
+ ```
301
+ /configure Auto-approve file writes and patches
302
+ ```
328
303
 
329
- - **exec_command**: Run a command without shell interpretation.
330
- - **write_file**: Write a file.
331
- - **patch_file**: Patch a file.
332
- - **tmux_command**: Run a tmux command.
333
- - **ask_web**: Use the web search to answer questions that need up-to-date information or supporting sources. (requires Google API key or Vertex AI configuration).
334
- - **ask_url**: Use one or more provided URLs to answer a question. Include the URLs in your question. (requires Google API key or Vertex AI configuration).
335
- - **delegate_to_subagent**: Delegate a subtask to a subagent. The agent switches to a subagent role within the same conversation, focusing on the specified goal.
336
- - **report_as_subagent**: Report completion and return to the main agent. Used by subagents to communicate results and restore the main agent role. After reporting, the subagent's conversation history is removed from the context.
337
- - **compact_context**: Compact the conversation context by discarding prior messages and reloading task state from a memory file. Use when the context has grown large but the task is not yet complete. Can also be invoked via the `/compact` slash command.
304
+ ```
305
+ /configure Set up a sandbox for this project
306
+ ```
338
307
 
339
308
  ## Configuration
340
309
 
310
+ Files are loaded in the following order. Settings in later files override earlier ones.
311
+
341
312
  ```
342
313
  ~/.config/plain-agent/
343
- \__ config.json # User configuration
344
- \__ config.local.json # User local configuration (including secrets)
345
- \__ prompts/ # Global/User-defined prompts
346
- \__ agents/ # Global/User-defined agent roles
314
+ ├── (1) config.json # User configuration
315
+ ├── (2) config.local.json # User local configuration (including secrets)
316
+ ├── prompts/ # Global/User-defined prompts
317
+ └── agents/ # Global/User-defined agent roles
347
318
 
348
319
  <project-root>
349
- \__ .plain-agent/
350
- \__ config.json # Project-specific configuration
351
- \__ config.local.json # Project-specific local configuration (including secrets)
352
- \__ memory/ # Task-specific memory files
353
- \__ prompts/ # Project-specific prompts
354
- \__ agents/ # Project-specific agent roles
320
+ └── .plain-agent/
321
+ ├── (3) config.json # Project-specific configuration
322
+ ├── (4) config.local.json # Project-specific local configuration (including secrets)
323
+ ├── memory/ # Task-specific memory files
324
+ ├── prompts/ # Project-specific prompts
325
+ └── agents/ # Project-specific agent roles
355
326
  ```
356
327
 
357
- The agent loads configuration files in the following order. Settings in later files will override those in earlier files.
358
-
359
- - `~/.config/plain-agent/config.json`
360
- - `~/.config/plain-agent/config.local.json`
361
- - `.plain-agent/config.json`
362
- - `.plain-agent/config.local.json`
363
-
364
328
  ### Example
365
329
 
366
330
  <details>
@@ -423,19 +387,19 @@ The agent loads configuration files in the following order. Settings in later fi
423
387
  "patterns": [
424
388
  {
425
389
  "toolName": { "$regex": "^(write_file|patch_file)$" },
426
- "input": { "filePath": { "$regex": "^(\\./)?\\.plain-agent/memory/.+\\.md$" } },
390
+ "input": { "filePath": { "$regex": "^\\.plain-agent/memory/.+\\.md$" } },
427
391
  "action": "allow"
428
392
  },
429
393
  {
430
394
  "toolName": { "$regex": "^(write_file|patch_file)$" },
431
- "input": { "filePath": { "$regex": "^(\\./)?src/" } },
395
+ "input": { "filePath": { "$regex": "^src/" } },
432
396
  "action": "allow"
433
397
  },
434
398
 
435
399
  // ⚠️ Arbitrary code execution can access unauthorized files and networks. Always use a sandbox.
436
400
  {
437
401
  "toolName": "exec_command",
438
- "input": { "command": "npm", "args": ["run", { "$regex": "^(check|test|lint|fix)$" }] },
402
+ "input": { "command": "npm", "args": ["run", { "$regex": "^(lint|test)$" }] },
439
403
  "action": "allow"
440
404
  },
441
405
 
@@ -511,8 +475,8 @@ The agent loads configuration files in the following order. Settings in later fi
511
475
  }
512
476
  },
513
477
 
514
- // Override default notification command
515
- // "notifyCmd": "/path/to/notification-command"
478
+ // Override default notification command (falls back to terminal bell)
479
+ // "notifyCmd": { "command": "plain-notify-desktop", "args": [] }
516
480
 
517
481
  // (Optional) Voice input. See "Voice Input" below.
518
482
  // "voiceInput": {
@@ -523,10 +487,35 @@ The agent loads configuration files in the following order. Settings in later fi
523
487
  ```
524
488
  </details>
525
489
 
490
+ ## Available Tools
491
+
492
+ The agent can use the following tools to assist with tasks:
493
+
494
+ - **exec_command**: Run a command without shell interpretation.
495
+ - **write_file**: Write a file.
496
+ - **patch_file**: Patch a file.
497
+ - **tmux_command**: Run a tmux command.
498
+ - **ask_web**: Use the web search to answer questions that need up-to-date information or supporting sources. (requires Google API key or Vertex AI configuration).
499
+ - **ask_url**: Use one or more provided URLs to answer a question. Include the URLs in your question. (requires Google API key or Vertex AI configuration).
500
+ - **delegate_to_subagent**: Delegate a subtask to a subagent. The agent switches to a subagent role within the same conversation, focusing on the specified goal.
501
+ - **report_as_subagent**: Report completion and return to the main agent. Used by subagents to communicate results and restore the main agent role. After reporting, the subagent's conversation history is removed from the context.
502
+ - **compact_context**: Compact the conversation context by discarding prior messages and reloading task state from a memory file. Use when the context has grown large but the task is not yet complete. Can also be invoked via the `/compact` slash command.
503
+
526
504
  ## Prompts
527
505
 
528
506
  You can define reusable prompts in Markdown files.
529
507
 
508
+ ### Locations
509
+
510
+ The agent searches for prompts in the following directories:
511
+
512
+ - `~/.config/plain-agent/prompts/`
513
+ - `.plain-agent/prompts/`
514
+ - `.claude/commands/`
515
+ - `.claude/skills/`
516
+
517
+ The prompt ID is the relative path of the file without the `.md` extension. For example, `.plain-agent/prompts/commit.md` becomes `/prompts:commit`.
518
+
530
519
  ### Prompt File Format
531
520
 
532
521
  ```md
@@ -548,30 +537,8 @@ import: https://raw.githubusercontent.com/anthropics/claude-code/5cff78741f54a0d
548
537
  - Parallel execution of subagents is not supported. Delegate to subagents sequentially.
549
538
  ```
550
539
 
551
- ```md
552
- ---
553
- import: https://raw.githubusercontent.com/anthropics/claude-code/db8834ba1d72e9a26fba30ac85f3bc4316bb0689/plugins/code-review/commands/code-review.md
554
- ---
555
-
556
- - Parallel execution of subagents is not supported. Delegate to subagents sequentially.
557
- - If CLAUDE.md is not found, refer to AGENTS.md instead for project rules and conventions.
558
- - If the PR branch is already checked out, review changes from local files instead of fetching from GitHub.
559
- - After explaining the review results to the user, ask whether to post the comments to GitHub as well.
560
- ```
561
-
562
540
  Remote prompts are fetched and cached locally. The local content will be appended to the imported content.
563
541
 
564
- ### Locations
565
-
566
- The agent searches for prompts in the following directories:
567
-
568
- - `~/.config/plain-agent/prompts/`
569
- - `.plain-agent/prompts/`
570
- - `.claude/commands/`
571
- - `.claude/skills/`
572
-
573
- The prompt ID is the relative path of the file without the `.md` extension. For example, `.plain-agent/prompts/commit.md` becomes `/prompts:commit`.
574
-
575
542
  ### Shortcuts
576
543
 
577
544
  Prompts located in a `shortcuts/` subdirectory (e.g., `.plain-agent/prompts/shortcuts/commit.md`) can be invoked directly as a top-level command (e.g., `/commit`).
@@ -580,6 +547,14 @@ Prompts located in a `shortcuts/` subdirectory (e.g., `.plain-agent/prompts/shor
580
547
 
581
548
  Subagents are specialized agents designed for specific tasks.
582
549
 
550
+ ### Locations
551
+
552
+ The agent searches for subagent definitions in the following directories:
553
+
554
+ - `~/.config/plain-agent/agents/`
555
+ - `.plain-agent/agents/`
556
+ - `.claude/agents/`
557
+
583
558
  ### Subagent File Format
584
559
 
585
560
  ```md
@@ -602,14 +577,6 @@ Use AGENTS.md instead of CLAUDE.md in this project.
602
577
 
603
578
  Remote subagents are fetched and cached locally. The local content will be appended to the imported content.
604
579
 
605
- ### Locations
606
-
607
- The agent searches for subagent definitions in the following directories:
608
-
609
- - `~/.config/plain-agent/agents/`
610
- - `.plain-agent/agents/`
611
- - `.claude/agents/`
612
-
613
580
  ## Claude Code Plugin Support
614
581
 
615
582
  Example:
@@ -653,9 +620,10 @@ and send them like regular text.
653
620
 
654
621
  ### Providers
655
622
 
656
- **OpenAI Realtime** (default, recommended):
623
+ **OpenAI Realtime**
657
624
 
658
625
  ```js
626
+ // ~/.config/plain-agent/config.local.json
659
627
  {
660
628
  "voiceInput": {
661
629
  "provider": "openai",
@@ -666,9 +634,10 @@ and send them like regular text.
666
634
  }
667
635
  ```
668
636
 
669
- **Gemini Live** (preview API; model names and pricing may change):
637
+ **Gemini Live**
670
638
 
671
639
  ```js
640
+ // ~/.config/plain-agent/config.local.json
672
641
  {
673
642
  "voiceInput": {
674
643
  "provider": "gemini",
@@ -683,8 +652,7 @@ and send them like regular text.
683
652
 
684
653
  - `toggleKey` — Rebind the toggle. Accepts `"ctrl-<char>"` where `<char>`
685
654
  is a letter (a-z) or one of `[ \ ] ^ _`. Defaults to `"ctrl-o"`.
686
- - `recorder` — Override recorder auto-detection. Must write raw 16-bit
687
- little-endian mono PCM to stdout at 24 kHz (OpenAI) or 16 kHz (Gemini).
655
+ - `recorder` — Override recorder auto-detection, e.g. `{ "command": "sox", "args": ["-q", "-d", "-b", "16", "-c", "1", "-r", "24000", "-e", "signed-integer", "-t", "raw", "-"] }`. Must write raw 16-bit little-endian mono PCM to stdout at 24 kHz (OpenAI) or 16 kHz (Gemini).
688
656
 
689
657
  ## Development
690
658
 
@@ -705,13 +673,9 @@ npx npm-check-updates -t minor -c 3 -u
705
673
  ## Release
706
674
 
707
675
  ```sh
708
- npm run check
709
-
710
- git commit -m "<message>"
711
-
712
676
  npm version <major|minor|patch>
713
- git push --follow-tags
714
677
 
678
+ git push --follow-tags
715
679
  gh release create $(git describe --tags) --generate-notes
716
680
 
717
681
  npm publish --access public
@@ -63,9 +63,10 @@ Present the analysis results and ask the user to confirm. Show:
63
63
  3. **Volume configuration** (e.g., "node_modules + npm cache")
64
64
  4. **Setup install command** (e.g., "npm ci")
65
65
 
66
- Ask only one additional question:
66
+ Ask the following questions one at a time, waiting for the user's answer before proceeding to the next:
67
67
 
68
- > Do you want to mount `~/.gitconfig` into the sandbox? (This allows git commit inside the sandbox.)
68
+ 1. Do you want to mount `~/.gitconfig` into the sandbox? (This allows git commit inside the sandbox.)
69
+ 2. Are there any commands that must run on the host instead of inside the container? (e.g. `gh`, `docker` — tools that require host credentials or sockets.) If so, which ones?
69
70
 
70
71
  ## Step 3: Generate run.sh
71
72
 
@@ -115,7 +116,7 @@ set -eu -o pipefail
115
116
 
116
117
  this_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
117
118
 
118
- # Setup sandbox (install runtime and dependencies with network access)
119
+ # Build Docker image and setup sandbox (install runtime and dependencies with network access)
119
120
  "$this_dir/sandbox/run.sh" --verbose --allow-net 0.0.0.0/0 mise use node@lts
120
121
  "$this_dir/sandbox/run.sh" --verbose --allow-net 0.0.0.0/0 npm ci
121
122
 
@@ -125,21 +126,19 @@ npm ci
125
126
 
126
127
  `--allow-net 0.0.0.0/0` is needed only during setup for downloading packages. It should NOT be in run.sh for normal usage.
127
128
 
128
- ## Step 5: Show config.json Example
129
+ ## Step 5: Update config.json
129
130
 
130
- After generating all files, instruct the user to add the following to their `.plain-agent/config.json`:
131
+ Show the user the following config and explain:
132
+
133
+ - `--skip-build` assumes the image is already built (run `setup.sh` first to build)
134
+ - `--keep-alive 30` reuses the container for 30 seconds between commands for performance
135
+
136
+ If the user specified any unsandboxed commands in Step 2, also include and explain:
137
+
138
+ - They run **unsandboxed** because they need host access.
131
139
 
132
140
  ```json
133
141
  {
134
- "autoApproval": {
135
- "patterns": [
136
- {
137
- "toolName": "exec_command",
138
- "input": { "command": { "$regex": "^(gh|docker)$" } },
139
- "action": "ask"
140
- }
141
- ]
142
- },
143
142
  "sandbox": {
144
143
  "command": ".plain-agent/sandbox/run.sh",
145
144
  "args": ["--skip-build", "--keep-alive", "30"],
@@ -154,7 +153,6 @@ After generating all files, instruct the user to add the following to their `.pl
154
153
  }
155
154
  ```
156
155
 
157
- If the project already has a `.plain-agent/config.json`, show only the keys that should be added/merged. Remind the user:
158
- - `--skip-build` assumes the image is already built (run `setup.sh` first to build)
159
- - `--keep-alive 30` reuses the container for 30 seconds between commands for performance
160
- - `gh` and `docker` run unsandboxed (host access needed), so they should also be set to `ask` in `autoApproval` to avoid being auto-approved alongside other shell commands. Place this `ask` pattern before any broad `allow` pattern for `exec_command`, since `autoApproval` patterns are evaluated in order and the first match wins.
156
+ Adjust the regex to match the commands the user specified. If none, omit `sandbox.rules`.
157
+
158
+ After the user confirms, write the config into `.plain-agent/config.json` (merge if the file already exists).
@@ -813,7 +813,7 @@
813
813
  }
814
814
  },
815
815
  {
816
- "name": "gpt-5.4",
816
+ "name": "gpt-5.5",
817
817
  "variant": "thinking-medium",
818
818
  "platform": {
819
819
  "name": "openai",
@@ -823,7 +823,7 @@
823
823
  "model": {
824
824
  "format": "openai-responses",
825
825
  "config": {
826
- "model": "gpt-5.4",
826
+ "model": "gpt-5.5",
827
827
  "reasoning": { "effort": "medium", "summary": "auto" },
828
828
  "store": false,
829
829
  "include": ["reasoning.encrypted_content"]
@@ -833,14 +833,14 @@
833
833
  "currency": "USD",
834
834
  "unit": "1M",
835
835
  "costs": {
836
- "input_tokens": 2.5,
837
- "input_tokens_details.cached_tokens": -2.25,
838
- "output_tokens": 15
836
+ "input_tokens": 5,
837
+ "input_tokens_details.cached_tokens": -4.5,
838
+ "output_tokens": 30
839
839
  }
840
840
  }
841
841
  },
842
842
  {
843
- "name": "gpt-5.4",
843
+ "name": "gpt-5.5",
844
844
  "variant": "thinking-high",
845
845
  "platform": {
846
846
  "name": "openai",
@@ -850,7 +850,7 @@
850
850
  "model": {
851
851
  "format": "openai-responses",
852
852
  "config": {
853
- "model": "gpt-5.4",
853
+ "model": "gpt-5.5",
854
854
  "reasoning": { "effort": "high", "summary": "auto" },
855
855
  "store": false,
856
856
  "include": ["reasoning.encrypted_content"]
@@ -860,14 +860,14 @@
860
860
  "currency": "USD",
861
861
  "unit": "1M",
862
862
  "costs": {
863
- "input_tokens": 2.5,
864
- "input_tokens_details.cached_tokens": -2.25,
865
- "output_tokens": 15
863
+ "input_tokens": 5,
864
+ "input_tokens_details.cached_tokens": -4.5,
865
+ "output_tokens": 30
866
866
  }
867
867
  }
868
868
  },
869
869
  {
870
- "name": "gpt-5.4",
870
+ "name": "gpt-5.5",
871
871
  "variant": "thinking-xhigh",
872
872
  "platform": {
873
873
  "name": "openai",
@@ -877,7 +877,7 @@
877
877
  "model": {
878
878
  "format": "openai-responses",
879
879
  "config": {
880
- "model": "gpt-5.4",
880
+ "model": "gpt-5.5",
881
881
  "reasoning": { "effort": "xhigh", "summary": "auto" },
882
882
  "store": false,
883
883
  "include": ["reasoning.encrypted_content"]
@@ -887,9 +887,9 @@
887
887
  "currency": "USD",
888
888
  "unit": "1M",
889
889
  "costs": {
890
- "input_tokens": 2.5,
891
- "input_tokens_details.cached_tokens": -2.25,
892
- "output_tokens": 15
890
+ "input_tokens": 5,
891
+ "input_tokens_details.cached_tokens": -4.5,
892
+ "output_tokens": 30
893
893
  }
894
894
  }
895
895
  },
@@ -0,0 +1,60 @@
1
+ ---
2
+ description: Update plain-agent configuration based on user needs.
3
+ ---
4
+
5
+ Fetch the latest README and help the user configure plain-agent for this project. Before each step, briefly explain to the user what you are about to do and why.
6
+
7
+ ## Security Rule (Non-Negotiable)
8
+
9
+ **Never write credentials** (API keys, tokens, passwords, secrets) into any config file.
10
+
11
+ When a setting requires a credential:
12
+ 1. Tell the user it must go into `.plain-agent/config.local.json`.
13
+ 2. Show the exact JSON snippet they need to add.
14
+ 3. Do not modify that file yourself.
15
+
16
+ If the user wants a setting applied globally (`~/.config/plain-agent/`), show them the exact snippet and tell them to add it manually. Do not access the home directory.
17
+
18
+ ## Step 1: Fetch the Latest README
19
+
20
+ Fetch the latest README from GitHub as the authoritative reference for all configuration options:
21
+
22
+ ```sh
23
+ gh api --method GET -H "Accept: application/vnd.github.v3.raw" "repos/iinm/plain-agent/contents/README.md?ref=main"
24
+ ```
25
+
26
+ ## Step 2: Read the Current Config
27
+
28
+ ```sh
29
+ cat .plain-agent/config.json
30
+ ```
31
+
32
+ ## Step 3: Ask the User What They Want
33
+
34
+ Ask what the user wants to configure. Common topics:
35
+
36
+ - **Model** — which LLM to use (`model` field)
37
+ - **Auto-approval rules** — which tool calls to allow automatically (`autoApproval`)
38
+ - **Sandbox** — isolated execution environment (`sandbox`)
39
+ - **MCP servers** — external tool integrations (`mcpServers`)
40
+ - **Claude Code plugins** — reuse Claude Code plugin prompts/agents (`claudeCodePlugins`)
41
+ - **Voice input** — voice transcription settings (`voiceInput`)
42
+ - **Notifications** — custom notify command (`notifyCmd`)
43
+
44
+ If the request is vague, ask a focused clarifying question before proceeding.
45
+
46
+ **If the user wants to configure Sandbox**: immediately delegate to the `sandbox-configurator` agent and do not proceed further yourself.
47
+
48
+ ## Step 4: Apply Changes
49
+
50
+ Update `.plain-agent/config.json`. Rules:
51
+
52
+ - Merge carefully — preserve all existing keys.
53
+ - Only write to `.plain-agent/config.json`. Never access files outside the project directory.
54
+ - For credential-requiring fields, use a placeholder like `"<YOUR_API_KEY>"` and instruct the user to add the real value to `.plain-agent/config.local.json` themselves.
55
+
56
+ ## Step 5: Summarize
57
+
58
+ 1. Show a diff or summary of what changed.
59
+ 2. If any credentials were skipped, show the snippet the user needs to add to `config.local.json`.
60
+ 3. Tell the user to restart `plain` for changes to take effect.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iinm/plain-agent",
3
- "version": "1.7.19",
3
+ "version": "1.7.21",
4
4
  "description": "A lightweight CLI-based coding agent",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,9 +10,7 @@
10
10
  },
11
11
  "bin": {
12
12
  "plain": "./bin/plain",
13
- "plain-interrupt": "./bin/plain-interrupt",
14
13
  "plain-notify-desktop": "./bin/plain-notify-desktop",
15
- "plain-notify-terminal-bell": "./bin/plain-notify-terminal-bell",
16
14
  "plain-sandbox": "./sandbox/bin/plain-sandbox"
17
15
  },
18
16
  "files": [
package/src/agentLoop.mjs CHANGED
@@ -128,7 +128,9 @@ export function createAgentLoop({
128
128
 
129
129
  const { message: assistantMessage, providerTokenUsage } = modelOutput;
130
130
  stateManager.appendMessages([assistantMessage]);
131
- agentEventEmitter.emit("providerTokenUsage", providerTokenUsage);
131
+ if (providerTokenUsage) {
132
+ agentEventEmitter.emit("providerTokenUsage", providerTokenUsage);
133
+ }
132
134
 
133
135
  // Gemini may stop with "thinking" -> continue
134
136
  const lastContent = assistantMessage.content.at(-1);