@iinm/plain-agent 1.0.0
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/.config/agents.library/code-simplifier.md +5 -0
- package/.config/agents.library/qa-engineer.md +74 -0
- package/.config/agents.library/software-architect.md +278 -0
- package/.config/agents.predefined/worker.md +3 -0
- package/.config/config.predefined.json +825 -0
- package/.config/prompts.library/code-review.md +8 -0
- package/.config/prompts.library/feature-dev.md +6 -0
- package/.config/prompts.predefined/shortcuts/commit-by-user.md +9 -0
- package/.config/prompts.predefined/shortcuts/commit.md +10 -0
- package/.config/prompts.predefined/shortcuts/general-question.md +6 -0
- package/LICENSE +21 -0
- package/README.md +624 -0
- package/bin/plain +3 -0
- package/bin/plain-interrupt +6 -0
- package/bin/plain-notify-desktop +19 -0
- package/bin/plain-notify-terminal-bell +3 -0
- package/package.json +57 -0
- package/sandbox/bin/plain-sandbox +972 -0
- package/src/agent.d.ts +48 -0
- package/src/agent.mjs +159 -0
- package/src/agentLoop.mjs +369 -0
- package/src/agentState.mjs +41 -0
- package/src/cliArgs.mjs +45 -0
- package/src/cliFormatter.mjs +217 -0
- package/src/cliInteractive.mjs +739 -0
- package/src/config.d.ts +48 -0
- package/src/config.mjs +168 -0
- package/src/context/consumeInterruptMessage.mjs +30 -0
- package/src/context/loadAgentRoles.mjs +272 -0
- package/src/context/loadPrompts.mjs +312 -0
- package/src/context/loadUserMessageContext.mjs +147 -0
- package/src/env.mjs +46 -0
- package/src/main.mjs +202 -0
- package/src/mcp.mjs +202 -0
- package/src/model.d.ts +109 -0
- package/src/modelCaller.mjs +29 -0
- package/src/modelDefinition.d.ts +73 -0
- package/src/prompt.mjs +128 -0
- package/src/providers/anthropic.d.ts +248 -0
- package/src/providers/anthropic.mjs +596 -0
- package/src/providers/gemini.d.ts +208 -0
- package/src/providers/gemini.mjs +752 -0
- package/src/providers/openai.d.ts +281 -0
- package/src/providers/openai.mjs +551 -0
- package/src/providers/openaiCompatible.d.ts +147 -0
- package/src/providers/openaiCompatible.mjs +658 -0
- package/src/providers/platform/azure.mjs +42 -0
- package/src/providers/platform/bedrock.mjs +74 -0
- package/src/providers/platform/googleCloud.mjs +34 -0
- package/src/subagent.mjs +247 -0
- package/src/tmpfile.mjs +27 -0
- package/src/tool.d.ts +74 -0
- package/src/toolExecutor.mjs +236 -0
- package/src/toolInputValidator.mjs +183 -0
- package/src/toolUseApprover.mjs +98 -0
- package/src/tools/askGoogle.mjs +135 -0
- package/src/tools/delegateToSubagent.d.ts +4 -0
- package/src/tools/delegateToSubagent.mjs +48 -0
- package/src/tools/execCommand.d.ts +22 -0
- package/src/tools/execCommand.mjs +200 -0
- package/src/tools/fetchWebPage.mjs +96 -0
- package/src/tools/patchFile.d.ts +4 -0
- package/src/tools/patchFile.mjs +96 -0
- package/src/tools/reportAsSubagent.d.ts +3 -0
- package/src/tools/reportAsSubagent.mjs +44 -0
- package/src/tools/tavilySearch.d.ts +6 -0
- package/src/tools/tavilySearch.mjs +57 -0
- package/src/tools/tmuxCommand.d.ts +14 -0
- package/src/tools/tmuxCommand.mjs +194 -0
- package/src/tools/writeFile.d.ts +4 -0
- package/src/tools/writeFile.mjs +56 -0
- package/src/utils/evalJSONConfig.mjs +48 -0
- package/src/utils/matchValue.d.ts +6 -0
- package/src/utils/matchValue.mjs +40 -0
- package/src/utils/noThrow.mjs +31 -0
- package/src/utils/notify.mjs +28 -0
- package/src/utils/parseFileRange.mjs +18 -0
- package/src/utils/readFileRange.mjs +33 -0
- package/src/utils/retryOnError.mjs +41 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
import: https://raw.githubusercontent.com/anthropics/claude-code/db8834ba1d72e9a26fba30ac85f3bc4316bb0689/plugins/code-review/commands/code-review.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
- Parallel execution of subagents is not supported. Delegate to subagents sequentially.
|
|
6
|
+
- If CLAUDE.md is not found, refer to AGENTS.md instead for project rules and conventions.
|
|
7
|
+
- If the PR branch is already checked out, review changes from local files instead of fetching from GitHub.
|
|
8
|
+
- After explaining the review results to the user, ask whether to post the comments to GitHub as well.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
import: https://raw.githubusercontent.com/anthropics/claude-code/5cff78741f54a0dcfaeb11d29b9ea9a83f3882ff/plugins/feature-dev/commands/feature-dev.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
- Use memory file instead of TodoWrite
|
|
6
|
+
- Parallel execution of subagents is not supported. Delegate to subagents sequentially.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a commit message based on staged changes
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Create a commit.
|
|
6
|
+
- Understand the staged changes: git ["diff", "--staged"]
|
|
7
|
+
- Check the commit message format: git ["log", "--no-merges", "--oneline", "-n", "10"]
|
|
8
|
+
- Create a concise and descriptive commit message that follows the project's commit convention.
|
|
9
|
+
- Create a commit: git ["commit", "-m", "<commit message>"]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a commit message with Co-authored-by trailer
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Create a commit.
|
|
6
|
+
- Understand the staged changes: git ["diff", "--staged"]
|
|
7
|
+
- Check the commit message format: git ["log", "--no-merges", "--oneline", "-n", "10"]
|
|
8
|
+
- Create a concise and descriptive commit message that follows the project's commit convention.
|
|
9
|
+
- Create a commit:
|
|
10
|
+
exec_command: git ["commit", "-m", "<commit message>", "-m", "", "-m", "Co-authored-by: Plain Agent <plain-agent+<model-name>@localhost>"]
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Shumpei IINUMA
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
# Plain Agent
|
|
2
|
+
|
|
3
|
+
A lightweight CLI-based coding agent.
|
|
4
|
+
|
|
5
|
+
- **Safety controls** — Configure per-tool approval rules and run in a sandbox for stronger isolation
|
|
6
|
+
- **Multi-provider** — Works with Anthropic, OpenAI, Gemini, AWS Bedrock, Azure, Vertex AI, and more
|
|
7
|
+
- **Sequential subagent delegation** — Delegate subtasks to specialized subagents with full visibility into their actions
|
|
8
|
+
- **MCP support** — Connect to external MCP servers to extend available tools
|
|
9
|
+
- **Claude Code compatible** *(experimental)* — Reuse Claude Code plugins, agents, commands, and skills
|
|
10
|
+
|
|
11
|
+
## Safety Controls
|
|
12
|
+
|
|
13
|
+
This CLI tool automatically allows the execution of certain tools but requires explicit approval for security-sensitive operations, such as accessing parent directories.
|
|
14
|
+
The security rules are defined in [`config.predefined.json`](https://github.com/iinm/plain-agent/blob/main/.config/config.predefined.json) and [`toolInputValidator.mjs`](https://github.com/iinm/plain-agent/blob/main/src/toolInputValidator.mjs) within this repository.
|
|
15
|
+
|
|
16
|
+
⚠️ The `write_file` and `patch_file` tools block direct access to git-ignored files. However, `exec_command` can access any files in your environment.
|
|
17
|
+
Use a sandbox for stronger isolation.
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Linux or macOS
|
|
22
|
+
- Node.js 22 or later
|
|
23
|
+
- LLM provider credentials (API keys, AWS SSO, gcloud CLI, or Azure CLI)
|
|
24
|
+
- [ripgrep](https://github.com/burntsushi/ripgrep)
|
|
25
|
+
- [fd](https://github.com/sharkdp/fd)
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npm install -g @iinm/plain-agent
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
List available models.
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
curl https://raw.githubusercontent.com/iinm/plain-agent/refs/heads/main/.config/config.predefined.json \
|
|
37
|
+
| jq -r '.models[] | "\(.name)+\(.variant)"'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Create the configuration.
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
// ~/.config/config.local.json
|
|
44
|
+
{
|
|
45
|
+
// Default model used by ./bin/agent
|
|
46
|
+
"model": "gpt-5.4+thinking-high",
|
|
47
|
+
|
|
48
|
+
"platforms": [
|
|
49
|
+
{
|
|
50
|
+
"name": "anthropic",
|
|
51
|
+
"variant": "default",
|
|
52
|
+
"apiKey": "FIXME"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "gemini",
|
|
56
|
+
"variant": "default",
|
|
57
|
+
"apiKey": "FIXME"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "openai",
|
|
61
|
+
"variant": "default",
|
|
62
|
+
"apiKey": "FIXME"
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
|
|
66
|
+
// Optional
|
|
67
|
+
"tools": {
|
|
68
|
+
"askGoogle": {
|
|
69
|
+
"model": "gemini-3-flash-preview"
|
|
70
|
+
|
|
71
|
+
// Google AI Studio
|
|
72
|
+
"apiKey": "FIXME"
|
|
73
|
+
|
|
74
|
+
// Or use Vertex AI (Requires gcloud CLI to get authentication token)
|
|
75
|
+
// "platform": "vertex-ai",
|
|
76
|
+
// "baseURL": "https://aiplatform.googleapis.com/v1beta1/projects/<project_id>/locations/<location>",
|
|
77
|
+
},
|
|
78
|
+
"tavily": {
|
|
79
|
+
"apiKey": "FIXME"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
<details>
|
|
87
|
+
<summary>Extra provider examples</summary>
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
{
|
|
91
|
+
"platforms": [
|
|
92
|
+
{
|
|
93
|
+
// Requires Azure CLI to get access token
|
|
94
|
+
"name": "azure",
|
|
95
|
+
"variant": "default",
|
|
96
|
+
"baseURL": "https://<resource>.openai.azure.com/openai",
|
|
97
|
+
// Optional
|
|
98
|
+
"azureConfigDir": "/home/xxx/.azure-for-agent"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "bedrock",
|
|
102
|
+
"variant": "default",
|
|
103
|
+
"baseURL": "https://bedrock-runtime.<region>.amazonaws.com",
|
|
104
|
+
"awsProfile": "FIXME"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
// Requires gcloud CLI to get authentication token
|
|
108
|
+
"name": "vertex-ai",
|
|
109
|
+
"variant": "default",
|
|
110
|
+
"baseURL": "https://aiplatform.googleapis.com/v1beta1/projects/<project>/locations/<location>",
|
|
111
|
+
// Optional
|
|
112
|
+
"account": "<service_account_email>"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "openai",
|
|
116
|
+
"variant": "ollama",
|
|
117
|
+
"baseURL": "https://ollama.com",
|
|
118
|
+
"apiKey": "FIXME"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "openai",
|
|
122
|
+
"variant": "huggingface",
|
|
123
|
+
"baseURL": "https://router.huggingface.co",
|
|
124
|
+
"apiKey": "FIXME"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "openai",
|
|
128
|
+
"variant": "xai",
|
|
129
|
+
"apiKey": "FIXME"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
</details>
|
|
135
|
+
|
|
136
|
+
Run the agent.
|
|
137
|
+
|
|
138
|
+
```sh
|
|
139
|
+
plain
|
|
140
|
+
|
|
141
|
+
# Or specify a specific model
|
|
142
|
+
plain -m <model>+<variant>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Display the help message.
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
/help
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Interrupt the agent while it's running by providing additional instructions:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
plain-interrupt Stop and report the progress
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Available Tools
|
|
158
|
+
|
|
159
|
+
The agent can use the following tools to assist with tasks:
|
|
160
|
+
|
|
161
|
+
- **exec_command**: Run a command without shell interpretation.
|
|
162
|
+
- **write_file**: Write a file.
|
|
163
|
+
- **patch_file**: Patch a file.
|
|
164
|
+
- **tmux_command**: Run a tmux command.
|
|
165
|
+
- **fetch_web_page**: Fetch and extract web page content from a given URL, returning it as Markdown.
|
|
166
|
+
- **search_web**: Search the web for information (requires Tavily API key).
|
|
167
|
+
- **ask_google**: Ask Google a question using natural language (requires Gemini API key).
|
|
168
|
+
- **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.
|
|
169
|
+
- **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.
|
|
170
|
+
|
|
171
|
+
## Directory Structure
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
~/.config/plain-agent/
|
|
175
|
+
\__ config.json # User configuration
|
|
176
|
+
\__ config.local.json # User local configuration (including secrets)
|
|
177
|
+
\__ prompts/ # Global/User-defined prompts
|
|
178
|
+
\__ agents/ # Global/User-defined agent roles
|
|
179
|
+
|
|
180
|
+
<project-root>
|
|
181
|
+
\__ .plain-agent/
|
|
182
|
+
\__ config.json # Project-specific configuration
|
|
183
|
+
\__ config.local.json # Project-specific local configuration (including secrets)
|
|
184
|
+
\__ interrupt-message.txt # Interrupt message consumed by the agent
|
|
185
|
+
\__ memory/ # Task-specific memory files
|
|
186
|
+
\__ prompts/ # Project-specific prompts
|
|
187
|
+
\__ agents/ # Project-specific agent roles
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Configuration
|
|
191
|
+
|
|
192
|
+
The agent loads configuration files in the following order. Settings in later files will override those in earlier files.
|
|
193
|
+
|
|
194
|
+
- `~/.config/plain-agent/config.json`: User configuration for all projects.
|
|
195
|
+
- `~/.config/plain-agent/config.local.json`: User local configuration, typically for API keys.
|
|
196
|
+
- `.plain-agent/config.json`: Project-specific configuration.
|
|
197
|
+
- `.plain-agent/config.local.json`: Project-specific local configuration, typically for API keys or local development overrides.
|
|
198
|
+
|
|
199
|
+
### Example
|
|
200
|
+
|
|
201
|
+
<details>
|
|
202
|
+
<summary>YOLO mode example (requires sandbox for safety)</summary>
|
|
203
|
+
|
|
204
|
+
```js
|
|
205
|
+
{
|
|
206
|
+
"autoApproval": {
|
|
207
|
+
// Automatically deny unmatched tools instead of asking
|
|
208
|
+
"defaultAction": "deny",
|
|
209
|
+
// The maximum number of automatic approvals.
|
|
210
|
+
"maxApprovals": 100,
|
|
211
|
+
// Patterns are evaluated in order. First match wins.
|
|
212
|
+
"patterns": [
|
|
213
|
+
// Prohibit direct access to external URLs
|
|
214
|
+
{
|
|
215
|
+
"toolName": "fetch_web_page",
|
|
216
|
+
"action": "deny",
|
|
217
|
+
"reason": "Use ask_google instead"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"toolName": { "$regex": "^(write_file|patch_file)$" },
|
|
221
|
+
"action": "allow"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"toolName": { "$regex": "^(exec_command|tmux_command)$" },
|
|
225
|
+
"action": "allow"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"toolName": "ask_google",
|
|
229
|
+
"action": "allow"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ⚠️ Never do this. fetch_web_page and mcp run outside the sandbox, so they can send anything externally.
|
|
233
|
+
// {
|
|
234
|
+
// "toolName": { "$regex": "." },
|
|
235
|
+
// "action": "allow"
|
|
236
|
+
// }
|
|
237
|
+
]
|
|
238
|
+
},
|
|
239
|
+
"sandbox": {
|
|
240
|
+
"command": "plain-sandbox",
|
|
241
|
+
"args": ["--dockerfile", ".agent/sandbox/Dockerfile", "--allow-write", "--skip-build", "--keep-alive", "30"],
|
|
242
|
+
"separator": "--",
|
|
243
|
+
"rules": [
|
|
244
|
+
{
|
|
245
|
+
"pattern": {
|
|
246
|
+
"command": "npm",
|
|
247
|
+
"args": ["ci"]
|
|
248
|
+
},
|
|
249
|
+
"mode": "sandbox",
|
|
250
|
+
"extraArgs": ["--allow-net", "0.0.0.0/0"]
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
</details>
|
|
257
|
+
|
|
258
|
+
<details>
|
|
259
|
+
<summary>Full example</summary>
|
|
260
|
+
|
|
261
|
+
```js
|
|
262
|
+
{
|
|
263
|
+
"autoApproval": {
|
|
264
|
+
// The maximum number of automatic approvals.
|
|
265
|
+
"maxApprovals": 50,
|
|
266
|
+
// Patterns are evaluated in order. First match wins.
|
|
267
|
+
"patterns": [
|
|
268
|
+
{
|
|
269
|
+
"toolName": { "$regex": "^(write_file|patch_file)$" },
|
|
270
|
+
"input": { "filePath": { "$regex": "^\\.plain-agent/memory/.+\\.md$" } },
|
|
271
|
+
"action": "allow"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"toolName": { "$regex": "^(write_file|patch_file)$" },
|
|
275
|
+
"input": { "filePath": { "$regex": "^(\\./)?src/" } },
|
|
276
|
+
"action": "allow"
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
// ⚠️ `npm run test` may execute arbitrary code and access git-ignored files.
|
|
280
|
+
// It must be run in a sandbox.
|
|
281
|
+
{
|
|
282
|
+
"toolName": "exec_command",
|
|
283
|
+
"input": { "command": "npm", "args": ["run", { "$regex": "^(check|test|lint|fix)$" }] },
|
|
284
|
+
"action": "allow"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"toolName": "ask_google",
|
|
288
|
+
"action": "allow"
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
// MCP Tool naming convention: mcp__<serverName>__<toolName>
|
|
292
|
+
{
|
|
293
|
+
"toolName": { "$regex": "slack_(read|search)_.+" },
|
|
294
|
+
"action": "allow"
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
// (Optional) Sandbox environment for the exec_command and tmux_command tools
|
|
300
|
+
// https://github.com/iinm/plain-agent/tree/main/sandbox
|
|
301
|
+
"sandbox": {
|
|
302
|
+
"command": "plain-sandbox",
|
|
303
|
+
"args": ["--dockerfile", ".agent/sandbox/Dockerfile", "--allow-write", "--skip-build", "--keep-alive", "30"],
|
|
304
|
+
// separator is inserted between sandbox flags and the user command to prevent bypasses
|
|
305
|
+
"separator": "--",
|
|
306
|
+
|
|
307
|
+
"rules": [
|
|
308
|
+
// Run specific commands outside the sandbox
|
|
309
|
+
{
|
|
310
|
+
"pattern": {
|
|
311
|
+
"command": { "$regex": "^(gh|docker)$" }
|
|
312
|
+
},
|
|
313
|
+
"mode": "unsandboxed"
|
|
314
|
+
},
|
|
315
|
+
// Run commands in the sandbox with network access
|
|
316
|
+
{
|
|
317
|
+
"pattern": {
|
|
318
|
+
"command": "npm",
|
|
319
|
+
"args": ["install"]
|
|
320
|
+
},
|
|
321
|
+
"mode": "sandbox",
|
|
322
|
+
// Allow access to registry.npmjs.org
|
|
323
|
+
"additionalArgs": ["--allow-net", "registry.npmjs.org"]
|
|
324
|
+
}
|
|
325
|
+
]
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
// Configure MCP servers for extended functionality
|
|
329
|
+
"mcpServers": {
|
|
330
|
+
"chrome_devtools": {
|
|
331
|
+
"command": "npx",
|
|
332
|
+
"args": ["-y", "chrome-devtools-mcp@latest", "--isolated"]
|
|
333
|
+
},
|
|
334
|
+
// ⚠️ Add this to config.local.json to avoid committing secrets to Git
|
|
335
|
+
"slack": {
|
|
336
|
+
"command": "npx",
|
|
337
|
+
"args": ["-y", "mcp-remote", "https://mcp.slack.com/mcp", "--header", "Authorization:Bearer FIXME"],
|
|
338
|
+
},
|
|
339
|
+
"notion": {
|
|
340
|
+
"command": "npx",
|
|
341
|
+
"args": ["-y", "mcp-remote", "https://mcp.notion.com/mcp"],
|
|
342
|
+
"options": {
|
|
343
|
+
// Enable only specific tools (optional - if not specified, all tools are enabled)
|
|
344
|
+
"enabledTools": ["notion-search", "notion-fetch"]
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
"aws_knowledge": {
|
|
348
|
+
"command": "npx",
|
|
349
|
+
"args": ["-y", "mcp-remote", "https://knowledge-mcp.global.api.aws"]
|
|
350
|
+
},
|
|
351
|
+
// ⚠️ Add this to config.local.json to avoid committing secrets to Git
|
|
352
|
+
"google_developer-knowledge": {
|
|
353
|
+
"command": "npx",
|
|
354
|
+
"args": ["-y", "mcp-remote", "https://developerknowledge.googleapis.com/mcp", "--header", "X-Goog-Api-Key:FIXME"]
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
// Override default notification command
|
|
359
|
+
// "notifyCmd": "/path/to/notification-command"
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
</details>
|
|
363
|
+
|
|
364
|
+
## Prompts
|
|
365
|
+
|
|
366
|
+
You can define reusable prompts in Markdown files. These are especially useful for common tasks like creating commit messages or conducting retrospectives.
|
|
367
|
+
|
|
368
|
+
### Prompt File Format
|
|
369
|
+
|
|
370
|
+
Prompts are Markdown files with a YAML frontmatter:
|
|
371
|
+
|
|
372
|
+
```md
|
|
373
|
+
---
|
|
374
|
+
description: Create a commit message based on staged changes
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
Review the staged changes and create a concise commit message following the conventional commits specification.
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
You can also import remote prompts with the `import` field:
|
|
381
|
+
|
|
382
|
+
```md
|
|
383
|
+
---
|
|
384
|
+
import: https://raw.githubusercontent.com/anthropics/claude-code/5cff78741f54a0dcfaeb11d29b9ea9a83f3882ff/plugins/feature-dev/commands/feature-dev.md
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
- Use memory file instead of TodoWrite
|
|
388
|
+
- Parallel execution of subagents is not supported. Delegate to subagents sequentially.
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Remote prompts are fetched and cached locally. The local content will be appended to the imported content.
|
|
392
|
+
|
|
393
|
+
### Locations
|
|
394
|
+
|
|
395
|
+
The agent searches for prompts in the following directories:
|
|
396
|
+
|
|
397
|
+
- `~/.config/plain-agent/prompts/` (Global/User-defined prompts)
|
|
398
|
+
- `.plain-agent/prompts/` (Project-specific prompts)
|
|
399
|
+
- `.claude/commands/` (Claude-specific commands, prefixed with `claude/commands:`)
|
|
400
|
+
- `.claude/skills/` (Claude-specific skills, prefixed with `claude/skills:`)
|
|
401
|
+
|
|
402
|
+
The prompt ID is the relative path of the file without the `.md` extension. For example, `.plain-agent/prompts/retro.md` becomes `/prompts:retro`.
|
|
403
|
+
|
|
404
|
+
### Shortcuts
|
|
405
|
+
|
|
406
|
+
Prompts located in a `shortcuts/` subdirectory (e.g., `.plain-agent/prompts/shortcuts/review.md`) can be invoked directly as a top-level command (e.g., `/review`). This is useful for frequently used tasks. If a prompt is in a `shortcuts/` subdirectory, its ID is simplified by removing the `shortcuts/` prefix for use as a shortcut (e.g., `shortcuts/review` becomes `/review`).
|
|
407
|
+
|
|
408
|
+
## Subagents
|
|
409
|
+
|
|
410
|
+
Subagents are specialized agents that can be delegated specific tasks. They allow you to break down complex workflows into focused, manageable components.
|
|
411
|
+
|
|
412
|
+
### Subagent File Format
|
|
413
|
+
|
|
414
|
+
Subagent definitions are Markdown files with a YAML frontmatter:
|
|
415
|
+
|
|
416
|
+
```md
|
|
417
|
+
---
|
|
418
|
+
description: Simplifies and refines code for clarity and maintainability
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
You are a code simplifier. Your role is to refactor code while preserving its functionality.
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
You can also import remote subagent definitions with the `import` field:
|
|
425
|
+
|
|
426
|
+
```md
|
|
427
|
+
---
|
|
428
|
+
import: https://raw.githubusercontent.com/anthropics/claude-code/f7ab5c799caf2ec8c7cd1b99d2bc2f158459ef5e/plugins/pr-review-toolkit/agents/code-simplifier.md
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
Use AGENTS.md instead of CLAUDE.md in this project.
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Remote subagents are fetched and cached locally. The local content will be appended to the imported content.
|
|
435
|
+
|
|
436
|
+
### Locations
|
|
437
|
+
|
|
438
|
+
The agent searches for subagent definitions in the following directories:
|
|
439
|
+
|
|
440
|
+
- `~/.config/plain-agent/agents/` (Global/User-defined agents)
|
|
441
|
+
- `.plain-agent/agents/` (Project-specific agents)
|
|
442
|
+
- `.claude/agents/` (Claude-specific agents)
|
|
443
|
+
|
|
444
|
+
The subagent ID is the relative path of the file without the `.md` extension. For example, `.plain-agent/agents/worker.md` becomes `worker`.
|
|
445
|
+
|
|
446
|
+
## Claude Code Plugin Support
|
|
447
|
+
|
|
448
|
+
Example:
|
|
449
|
+
|
|
450
|
+
```sh
|
|
451
|
+
git clone --depth 1 https://github.com/anthropics/claude-code .plain-agent/claude-code-plugins/anthropics/claude-code
|
|
452
|
+
git clone --depth 1 https://github.com/awslabs/agent-plugins .plain-agent/claude-code-plugins/awslabs/agent-plugins
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
```js
|
|
456
|
+
// .plain-agent/config.json
|
|
457
|
+
{
|
|
458
|
+
"claudeCodePlugins": [
|
|
459
|
+
{ "name": "pr-review-toolkit", "path": "anthropics/claude-code/plugins/pr-review-toolkit" },
|
|
460
|
+
{ "name": "aws-serverless", "path": "awslabs/agent-plugins/plugins/aws-serverless" }
|
|
461
|
+
]
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## Development
|
|
467
|
+
|
|
468
|
+
```sh
|
|
469
|
+
# Run lint, typecheck, and test
|
|
470
|
+
npm run check
|
|
471
|
+
|
|
472
|
+
# Fix lint errors
|
|
473
|
+
npm run fix
|
|
474
|
+
# or
|
|
475
|
+
npm run fix -- --unsafe
|
|
476
|
+
|
|
477
|
+
# Update dependencies
|
|
478
|
+
npx npm-check-updates -t minor -c 3
|
|
479
|
+
npx npm-check-updates -t minor -c 3 -u
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Appendix: Creating Least-Privilege Users for Cloud Providers
|
|
483
|
+
|
|
484
|
+
<details>
|
|
485
|
+
<summary>Amazon Bedrock</summary>
|
|
486
|
+
|
|
487
|
+
```sh
|
|
488
|
+
# IAM Identity Center
|
|
489
|
+
identity_center_instance_arn="FIXME" # e.g., arn:aws:sso:::instance/ssoins-xxxxxxxxxxxxxxxx"
|
|
490
|
+
identity_store_id=FIXME
|
|
491
|
+
aws_account_id=FIXME
|
|
492
|
+
|
|
493
|
+
# Create a permission set
|
|
494
|
+
permission_set_arn=$(aws sso-admin create-permission-set \
|
|
495
|
+
--instance-arn "$identity_center_instance_arn" \
|
|
496
|
+
--name "BedrockForCodingAgent" \
|
|
497
|
+
--description "Allows only Bedrock model invocation" \
|
|
498
|
+
--query "PermissionSet.PermissionSetArn" --output text)
|
|
499
|
+
|
|
500
|
+
# Add a policy to the permission set
|
|
501
|
+
policy='{
|
|
502
|
+
"Version": "2012-10-17",
|
|
503
|
+
"Statement": [
|
|
504
|
+
{
|
|
505
|
+
"Effect": "Allow",
|
|
506
|
+
"Action": [
|
|
507
|
+
"bedrock:InvokeModel",
|
|
508
|
+
"bedrock:InvokeModelWithResponseStream"
|
|
509
|
+
],
|
|
510
|
+
"Resource": [
|
|
511
|
+
"arn:aws:bedrock:*::foundation-model/*",
|
|
512
|
+
"arn:aws:bedrock:*:*:inference-profile/*"
|
|
513
|
+
]
|
|
514
|
+
}
|
|
515
|
+
]
|
|
516
|
+
}'
|
|
517
|
+
|
|
518
|
+
aws sso-admin put-inline-policy-to-permission-set \
|
|
519
|
+
--instance-arn "$identity_center_instance_arn" \
|
|
520
|
+
--permission-set-arn "$permission_set_arn" \
|
|
521
|
+
--inline-policy "$policy"
|
|
522
|
+
|
|
523
|
+
# Create an SSO user
|
|
524
|
+
sso_user_name=FIXME
|
|
525
|
+
sso_user_email=FIXME
|
|
526
|
+
sso_user_family_name=FIXME
|
|
527
|
+
sso_user_given_name=FIXME
|
|
528
|
+
|
|
529
|
+
user_id=$(aws identitystore create-user \
|
|
530
|
+
--identity-store-id "$identity_store_id" \
|
|
531
|
+
--user-name "$sso_user_name" \
|
|
532
|
+
--display-name "$sso_user_name" \
|
|
533
|
+
--name "FamilyName=${sso_user_family_name},GivenName=${sso_user_given_name}" \
|
|
534
|
+
--emails Value=${sso_user_email},Primary=true \
|
|
535
|
+
--query "UserId" --output text)
|
|
536
|
+
|
|
537
|
+
# Associate the user, permission set, and account
|
|
538
|
+
aws sso-admin create-account-assignment \
|
|
539
|
+
--instance-arn "$identity_center_instance_arn" \
|
|
540
|
+
--target-id "$aws_account_id" \
|
|
541
|
+
--target-type AWS_ACCOUNT \
|
|
542
|
+
--permission-set-arn "$permission_set_arn" \
|
|
543
|
+
--principal-type USER \
|
|
544
|
+
--principal-id "$user_id"
|
|
545
|
+
|
|
546
|
+
# Verify the setup
|
|
547
|
+
aws configure sso
|
|
548
|
+
# profile: CodingAgent
|
|
549
|
+
|
|
550
|
+
profile=CodingAgent
|
|
551
|
+
aws sso login --profile "$profile"
|
|
552
|
+
|
|
553
|
+
echo '{"anthropic_version": "bedrock-2023-05-31", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello"}]}' > request.json
|
|
554
|
+
|
|
555
|
+
aws bedrock-runtime invoke-model \
|
|
556
|
+
--model-id global.anthropic.claude-haiku-4-5-20251001-v1:0 \
|
|
557
|
+
--body fileb://request.json \
|
|
558
|
+
--profile "$profile" \
|
|
559
|
+
--region ap-northeast-1 \
|
|
560
|
+
response.json
|
|
561
|
+
```
|
|
562
|
+
</details>
|
|
563
|
+
|
|
564
|
+
<details>
|
|
565
|
+
<summary>Azure - Microsoft Foundry</summary>
|
|
566
|
+
|
|
567
|
+
```sh
|
|
568
|
+
resource_group=FIXME
|
|
569
|
+
account_name=FIXME # resource name
|
|
570
|
+
|
|
571
|
+
# Create a service principal
|
|
572
|
+
service_principal=$(az ad sp create-for-rbac --name "CodingAgentServicePrincipal" --skip-assignment)
|
|
573
|
+
echo "$service_principal"
|
|
574
|
+
app_id=$(echo "$service_principal" | jq -r .appId)
|
|
575
|
+
|
|
576
|
+
# Assign role permissions
|
|
577
|
+
# https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/role-based-access-control?view=foundry-classic#azure-openai-roles
|
|
578
|
+
resource_id=$(az cognitiveservices account show \
|
|
579
|
+
--name "$account_name" \
|
|
580
|
+
--resource-group "$resource_group" \
|
|
581
|
+
--query id --output tsv)
|
|
582
|
+
|
|
583
|
+
az role assignment create \
|
|
584
|
+
--role "Cognitive Services OpenAI User" \
|
|
585
|
+
--assignee "$app_id" \
|
|
586
|
+
--scope "$resource_id"
|
|
587
|
+
|
|
588
|
+
# Log in with the service principal
|
|
589
|
+
export app_secret=$(echo "$service_principal" | jq -r .password)
|
|
590
|
+
export tenant_id=$(echo "$service_principal" | jq -r .tenant)
|
|
591
|
+
|
|
592
|
+
export AZURE_CONFIG_DIR=$HOME/.azure-for-agent # Change the location to store credentials
|
|
593
|
+
az login --service-principal -u "$app_id" -p "$app_secret" --tenant "$tenant_id"
|
|
594
|
+
```
|
|
595
|
+
</details>
|
|
596
|
+
|
|
597
|
+
<details>
|
|
598
|
+
<summary>Google Cloud Vertex AI</summary>
|
|
599
|
+
|
|
600
|
+
```sh
|
|
601
|
+
project_id=FIXME
|
|
602
|
+
service_account_name=FIXME
|
|
603
|
+
service_account_email="${service_account_name}@${project_id}.iam.gserviceaccount.com"
|
|
604
|
+
your_account_email=FIXME
|
|
605
|
+
|
|
606
|
+
# Create a service account
|
|
607
|
+
gcloud iam service-accounts create "$service_account_name" \
|
|
608
|
+
--project "$project_id" --display-name "Vertex AI Caller Service Account for Coding Agent"
|
|
609
|
+
|
|
610
|
+
# Grant permissions
|
|
611
|
+
gcloud projects add-iam-policy-binding "$project_id" \
|
|
612
|
+
--member "serviceAccount:$service_account_email" \
|
|
613
|
+
--role="roles/aiplatform.serviceAgent"
|
|
614
|
+
|
|
615
|
+
# Allow your account to impersonate the service account
|
|
616
|
+
gcloud iam service-accounts add-iam-policy-binding "$service_account_email" \
|
|
617
|
+
--project "$project_id" \
|
|
618
|
+
--member "user:$your_account_email" \
|
|
619
|
+
--role "roles/iam.serviceAccountTokenCreator"
|
|
620
|
+
|
|
621
|
+
# Verify that tokens can be issued
|
|
622
|
+
gcloud auth print-access-token --impersonate-service-account "$service_account_email"
|
|
623
|
+
```
|
|
624
|
+
</details>
|
package/bin/plain
ADDED