aru-code 0.3.0__tar.gz → 0.5.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.
Files changed (52) hide show
  1. {aru_code-0.3.0/aru_code.egg-info → aru_code-0.5.0}/PKG-INFO +179 -24
  2. {aru_code-0.3.0 → aru_code-0.5.0}/README.md +177 -23
  3. aru_code-0.5.0/aru/__init__.py +1 -0
  4. {aru_code-0.3.0 → aru_code-0.5.0}/aru/cli.py +237 -40
  5. aru_code-0.5.0/aru/config.py +463 -0
  6. aru_code-0.5.0/aru/permissions.py +507 -0
  7. {aru_code-0.3.0 → aru_code-0.5.0}/aru/providers.py +5 -4
  8. {aru_code-0.3.0 → aru_code-0.5.0}/aru/tools/codebase.py +115 -175
  9. {aru_code-0.3.0 → aru_code-0.5.0/aru_code.egg-info}/PKG-INFO +179 -24
  10. {aru_code-0.3.0 → aru_code-0.5.0}/aru_code.egg-info/SOURCES.txt +2 -0
  11. {aru_code-0.3.0 → aru_code-0.5.0}/aru_code.egg-info/requires.txt +1 -0
  12. {aru_code-0.3.0 → aru_code-0.5.0}/pyproject.toml +2 -1
  13. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli_completers.py +104 -2
  14. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_codebase.py +96 -18
  15. aru_code-0.5.0/tests/test_config.py +787 -0
  16. aru_code-0.5.0/tests/test_permissions.py +748 -0
  17. aru_code-0.3.0/aru/__init__.py +0 -1
  18. aru_code-0.3.0/aru/config.py +0 -239
  19. aru_code-0.3.0/tests/test_config.py +0 -378
  20. {aru_code-0.3.0 → aru_code-0.5.0}/LICENSE +0 -0
  21. {aru_code-0.3.0 → aru_code-0.5.0}/aru/agents/__init__.py +0 -0
  22. {aru_code-0.3.0 → aru_code-0.5.0}/aru/agents/base.py +0 -0
  23. {aru_code-0.3.0 → aru_code-0.5.0}/aru/agents/executor.py +0 -0
  24. {aru_code-0.3.0 → aru_code-0.5.0}/aru/agents/planner.py +0 -0
  25. {aru_code-0.3.0 → aru_code-0.5.0}/aru/context.py +0 -0
  26. {aru_code-0.3.0 → aru_code-0.5.0}/aru/tools/__init__.py +0 -0
  27. {aru_code-0.3.0 → aru_code-0.5.0}/aru/tools/ast_tools.py +0 -0
  28. {aru_code-0.3.0 → aru_code-0.5.0}/aru/tools/gitignore.py +0 -0
  29. {aru_code-0.3.0 → aru_code-0.5.0}/aru/tools/mcp_client.py +0 -0
  30. {aru_code-0.3.0 → aru_code-0.5.0}/aru/tools/ranker.py +0 -0
  31. {aru_code-0.3.0 → aru_code-0.5.0}/aru/tools/tasklist.py +0 -0
  32. {aru_code-0.3.0 → aru_code-0.5.0}/aru_code.egg-info/dependency_links.txt +0 -0
  33. {aru_code-0.3.0 → aru_code-0.5.0}/aru_code.egg-info/entry_points.txt +0 -0
  34. {aru_code-0.3.0 → aru_code-0.5.0}/aru_code.egg-info/top_level.txt +0 -0
  35. {aru_code-0.3.0 → aru_code-0.5.0}/setup.cfg +0 -0
  36. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_agents_base.py +0 -0
  37. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_ast_tools.py +0 -0
  38. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli.py +0 -0
  39. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli_advanced.py +0 -0
  40. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli_base.py +0 -0
  41. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli_new.py +0 -0
  42. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli_run_cli.py +0 -0
  43. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli_session.py +0 -0
  44. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_cli_shell.py +0 -0
  45. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_context.py +0 -0
  46. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_executor.py +0 -0
  47. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_gitignore.py +0 -0
  48. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_main.py +0 -0
  49. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_mcp_client.py +0 -0
  50. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_planner.py +0 -0
  51. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_providers.py +0 -0
  52. {aru_code-0.3.0 → aru_code-0.5.0}/tests/test_ranker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aru-code
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: A Claude Code clone built with Agno agents
5
5
  Author-email: Estevao <estevaofon@gmail.com>
6
6
  License-Expression: MIT
@@ -29,6 +29,7 @@ Requires-Dist: tree-sitter>=0.23
29
29
  Requires-Dist: tree-sitter-python>=0.23
30
30
  Requires-Dist: mcp>=1.0
31
31
  Requires-Dist: openai>=2.29.0
32
+ Requires-Dist: pytest-asyncio>=1.3.0
32
33
  Provides-Extra: dev
33
34
  Requires-Dist: pytest>=8.0; extra == "dev"
34
35
  Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
@@ -47,14 +48,8 @@ Dynamic: license-file
47
48
  # aru
48
49
 
49
50
  An intelligent coding assistant for the terminal, powered by LLMs and [Agno](https://github.com/agno-agi/agno) agents.
50
- </br></br>
51
- <img width="600" alt="image" src="https://github.com/user-attachments/assets/36001faa-3163-4374-84fd-da8704a4ed9d" />
52
-
53
-
54
-
55
- https://github.com/user-attachments/assets/17674bfc-3d49-4e25-bdc7-dc445d5a089d
56
-
57
51
 
52
+ ![0329(3)](https://github.com/user-attachments/assets/e84d5139-ebaa-4d12-bbae-628fae7dbc7a)
58
53
 
59
54
  ## Highlights
60
55
 
@@ -63,7 +58,7 @@ https://github.com/user-attachments/assets/17674bfc-3d49-4e25-bdc7-dc445d5a089d
63
58
  - **16 Integrated Tools** — File operations, code search, shell, web search, task delegation
64
59
  - **Task Planning** — Break down complex tasks into steps with automatic execution
65
60
  - **Multi-Provider** — Anthropic, OpenAI, Ollama, Groq, OpenRouter, DeepSeek, and others via custom configuration
66
- - **Custom Commands and Skills** — Extend aru via the `.agents/` directory
61
+ - **Custom Commands, Skills, and Agents** — Extend aru via the `.agents/` directory
67
62
  - **MCP Support** — Integration with Model Context Protocol servers
68
63
 
69
64
  ## Quick Start
@@ -108,6 +103,7 @@ That's it — `aru` is available globally after install.
108
103
  | `/mcp` | List available MCP servers and tools |
109
104
  | `/commands` | List custom commands |
110
105
  | `/skills` | List available skills |
106
+ | `/agents` | List custom agents |
111
107
  | `/sessions` | List recent sessions |
112
108
  | `/help` | Show all commands |
113
109
  | `! <command>` | Execute shell commands |
@@ -148,6 +144,7 @@ By default, aru uses **Claude Sonnet 4.6** (Anthropic). You can switch to any su
148
144
  | **OpenAI** | `/model openai/gpt-4o` | `OPENAI_API_KEY` | `pip install "aru-code[openai]"` |
149
145
  | **Groq** | `/model groq/llama-3.3-70b-versatile` | `GROQ_API_KEY` | `pip install "aru-code[groq]"` |
150
146
  | **OpenRouter** | `/model openrouter/deepseek/deepseek-chat-v3-0324` | `OPENROUTER_API_KEY` | `pip install "aru-code[openai]"` |
147
+ | **MiniMax** | `/model openrouter/minimax/minimax-m2.7` | `OPENROUTER_API_KEY` | `pip install "aru-code[openai]"` |
151
148
 
152
149
  To install all providers at once:
153
150
 
@@ -173,9 +170,10 @@ You can set the default provider/model in `aru.json` so you don't need to switch
173
170
 
174
171
  ```json
175
172
  {
176
- "models": {
177
- "default": "openrouter/deepseek/deepseek-chat-v3-0324",
173
+ "default_model": "openrouter/minimax/minimax-m2.7",
174
+ "model_aliases": {
178
175
  "minimax": "openrouter/minimax/minimax-m2.5",
176
+ "minimax-m2.7": "openrouter/minimax/minimax-m2.7",
179
177
  "deepseek-v3": "openrouter/deepseek/deepseek-chat-v3-0324",
180
178
  "sonnet-4-6": "anthropic/claude-sonnet-4-6",
181
179
  "opus-4-6": "anthropic/claude-opus-4-6"
@@ -183,7 +181,7 @@ You can set the default provider/model in `aru.json` so you don't need to switch
183
181
  }
184
182
  ```
185
183
 
186
- The `default` field sets the main model. The other fields are aliases that can be used with `/model <alias>`.
184
+ The `default_model` field sets the main model. The `model_aliases` are shortcuts that can be used with `/model <alias>`.
187
185
 
188
186
  #### Custom providers
189
187
 
@@ -194,12 +192,13 @@ You can configure custom providers with specific token limits:
194
192
  "providers": {
195
193
  "deepseek": {
196
194
  "models": {
197
- "deepseek-chat-v3-0324": {"id": "deepseek-chat-v3-0324", "max_tokens": 16384}
195
+ "deepseek-chat-v3-0324": { "max_tokens": 16384 }
198
196
  }
199
197
  },
200
198
  "openrouter": {
201
199
  "models": {
202
- "minimax/minimax-m2.5": {"id": "minimax/minimax-m2.5", "max_tokens": 65536}
200
+ "minimax/minimax-m2.5": { "max_tokens": 65536 },
201
+ "minimax/minimax-m2.7": { "max_tokens": 131072 }
203
202
  }
204
203
  }
205
204
  }
@@ -208,25 +207,96 @@ You can configure custom providers with specific token limits:
208
207
 
209
208
  ### Permissions (`aru.json`)
210
209
 
211
- The `aru.json` file in the project root controls which shell commands aru can execute **without asking for confirmation**:
210
+ Aru uses a granular permission system where each tool action resolves to one of three outcomes:
211
+
212
+ - **`allow`** — executes without asking
213
+ - **`ask`** — prompts for confirmation (once / always / no)
214
+ - **`deny`** — blocks the action silently
215
+
216
+ Configure permissions per tool category with glob patterns:
212
217
 
213
218
  ```json
214
219
  {
215
220
  "permission": {
216
- "allow": [
217
- "git *",
218
- "npm *",
219
- "pytest *",
220
- "python *",
221
- "uv run pytest *"
222
- ]
221
+ "*": "ask",
222
+ "read": "allow",
223
+ "glob": "allow",
224
+ "grep": "allow",
225
+ "list": "allow",
226
+ "edit": {
227
+ "*": "allow",
228
+ "*.env": "deny"
229
+ },
230
+ "write": {
231
+ "*": "allow",
232
+ "*.env": "deny"
233
+ },
234
+ "bash": {
235
+ "*": "ask",
236
+ "git *": "allow",
237
+ "npm *": "allow",
238
+ "pytest *": "allow",
239
+ "rm -rf *": "deny"
240
+ },
241
+ "web_search": "allow",
242
+ "web_fetch": "allow",
243
+ "delegate_task": "allow"
244
+ }
245
+ }
246
+ ```
247
+
248
+ #### Available categories
249
+
250
+ | Category | Matched against | Default |
251
+ |----------|----------------|---------|
252
+ | `read` | file path | `allow` |
253
+ | `edit` | file path | `ask` |
254
+ | `write` | file path | `ask` |
255
+ | `bash` | command string | safe prefixes = `allow`, rest = `ask` |
256
+ | `glob` | — | `allow` |
257
+ | `grep` | — | `allow` |
258
+ | `list` | — | `allow` |
259
+ | `web_search` | — | `allow` |
260
+ | `web_fetch` | URL | `allow` |
261
+ | `delegate_task` | — | `allow` |
262
+
263
+ #### Rule precedence
264
+
265
+ Rules use **last-match-wins** ordering. Place catch-all `"*"` first, then specific patterns:
266
+
267
+ ```json
268
+ {
269
+ "edit": {
270
+ "*": "allow",
271
+ "*.env": "deny",
272
+ "*.env.example": "allow"
223
273
  }
224
274
  }
225
275
  ```
226
276
 
227
- Each entry is a glob pattern. Any command that doesn't match a listed pattern will prompt for confirmation before executing.
277
+ #### Shorthands
278
+
279
+ ```json
280
+ "permission": "allow"
281
+ ```
282
+ Allows everything (equivalent to `--dangerously-skip-permissions`).
283
+
284
+ ```json
285
+ "permission": { "read": "allow", "edit": "ask" }
286
+ ```
287
+ String value applies to all patterns in that category.
288
+
289
+ #### Defaults
290
+
291
+ Without any `aru.json` config, aru applies safe defaults:
292
+ - Read-only tools (`read`, `glob`, `grep`, `list`) → `allow`
293
+ - Mutating tools (`edit`, `write`) → `ask`
294
+ - Bash → ~40 safe command prefixes auto-allowed (`ls`, `git status`, `grep`, etc.), rest → `ask`
295
+ - Sensitive files (`*.env`, `*.env.*`) → `deny` for read/edit/write (except `*.env.example`)
228
296
 
229
297
  > `aru.json` can also be placed at `.aru/config.json`.
298
+ >
299
+ > A full `aru.json` config reference here: [`aru.json`](./aru.json)
230
300
 
231
301
  ### AGENTS.md
232
302
 
@@ -236,14 +306,98 @@ Place an `AGENTS.md` file in your project root with custom instructions that wil
236
306
 
237
307
  ```
238
308
  .agents/
309
+ ├── agents/ # Custom agents with their own model, tools, and prompt
310
+ │ └── reviewer.md # Usage: /reviewer <args>
239
311
  ├── commands/ # Custom slash commands (filename = command name)
240
312
  │ └── deploy.md # Usage: /deploy <args>
241
313
  └── skills/ # Custom skills/personas
242
- └── review.md # Loaded as additional agent instructions
314
+ └── review/
315
+ └── SKILL.md
243
316
  ```
244
317
 
245
318
  Command files support frontmatter with `description` and the `$INPUT` template variable for arguments.
246
319
 
320
+ ### Custom Agents
321
+
322
+ Custom agents are Markdown files with YAML frontmatter stored in `.agents/agents/`. Each agent runs with its own system prompt, model, and tool set — unlike commands and skills, which reuse the General Agent.
323
+
324
+ ```markdown
325
+ ---
326
+ name: Code Reviewer
327
+ description: Review code for quality, bugs, and best practices
328
+ model: anthropic/claude-sonnet-4-5
329
+ tools: read_file, grep_search, glob_search, code_structure
330
+ max_turns: 15
331
+ mode: primary
332
+ ---
333
+
334
+ You are an expert code reviewer. Analyze code for bugs, security,
335
+ performance, and readability. Do NOT modify files.
336
+ ```
337
+
338
+ #### Frontmatter fields
339
+
340
+ | Field | Required | Description |
341
+ |-------|----------|-------------|
342
+ | `name` | Yes | Display name of the agent |
343
+ | `description` | Yes | When to use this agent (shown in `/agents` and tab completion) |
344
+ | `model` | No | Provider/model reference (e.g., `anthropic/claude-sonnet-4-5`). Defaults to session model |
345
+ | `tools` | No | Comma-separated tool names (allowlist) or JSON object for granular control (e.g., `{"bash": false}`). Defaults to all general tools |
346
+ | `max_turns` | No | Max tool calls before the agent stops. Default: 20 |
347
+ | `mode` | No | `primary` (invocable via `/name`) or `subagent` (only via `delegate_task`). Default: `primary` |
348
+ | `permission` | No | Permission overrides (same format as `aru.json` permission section). Replaces global rules for specified categories while the agent runs |
349
+
350
+ #### Invocation
351
+
352
+ ```
353
+ aru> /reviewer src/auth.py # invoke by slash + filename (without .md)
354
+ aru> /agents # list all custom agents
355
+ ```
356
+
357
+ #### Discovery paths
358
+
359
+ Agents are discovered from multiple locations (later overrides earlier):
360
+
361
+ 1. `~/.agents/agents/` — global (available in all projects)
362
+ 2. `~/.claude/agents/` — global (Claude Code compatible path)
363
+ 3. `.agents/agents/` — project-local
364
+ 4. `.claude/agents/` — project-local
365
+
366
+ #### Agent-level permissions
367
+
368
+ Agents can override global permission rules. Overrides replace the entire category — unspecified categories inherit from global config.
369
+
370
+ ```markdown
371
+ ---
372
+ name: Code Reviewer
373
+ description: Read-only code reviewer
374
+ permission:
375
+ edit: deny
376
+ write: deny
377
+ bash:
378
+ git diff *: allow
379
+ grep *: allow
380
+ ---
381
+ ```
382
+
383
+ You can also set agent permissions in `aru.json` (overrides frontmatter):
384
+
385
+ ```json
386
+ {
387
+ "agent": {
388
+ "reviewer": {
389
+ "permission": { "edit": "deny", "write": "deny" }
390
+ }
391
+ }
392
+ }
393
+ ```
394
+
395
+ Each agent gets its own isolated "always" memory — approvals during an agent's run don't carry over to the global scope.
396
+
397
+ #### Subagent mode
398
+
399
+ Agents with `mode: subagent` can be referenced by the LLM via `delegate_task(task, agent="name")` but are not directly invocable from the CLI.
400
+
247
401
  ### MCP Support (Model Context Protocol)
248
402
 
249
403
  Aru can load tools from MCP servers. Configure in `.aru/mcp_config.json`:
@@ -301,6 +455,7 @@ aru-code/
301
455
  │ ├── cli.py # Interactive CLI with streaming display
302
456
  │ ├── config.py # Configuration loader (AGENTS.md, .agents/)
303
457
  │ ├── providers.py # Multi-provider LLM abstraction
458
+ │ ├── permissions.py # Granular permission system (allow/ask/deny)
304
459
  │ ├── agents/
305
460
  │ │ ├── planner.py # Planning agent
306
461
  │ │ └── executor.py # Execution agent
@@ -1,14 +1,8 @@
1
1
  # aru
2
2
 
3
3
  An intelligent coding assistant for the terminal, powered by LLMs and [Agno](https://github.com/agno-agi/agno) agents.
4
- </br></br>
5
- <img width="600" alt="image" src="https://github.com/user-attachments/assets/36001faa-3163-4374-84fd-da8704a4ed9d" />
6
-
7
-
8
-
9
- https://github.com/user-attachments/assets/17674bfc-3d49-4e25-bdc7-dc445d5a089d
10
-
11
4
 
5
+ ![0329(3)](https://github.com/user-attachments/assets/e84d5139-ebaa-4d12-bbae-628fae7dbc7a)
12
6
 
13
7
  ## Highlights
14
8
 
@@ -17,7 +11,7 @@ https://github.com/user-attachments/assets/17674bfc-3d49-4e25-bdc7-dc445d5a089d
17
11
  - **16 Integrated Tools** — File operations, code search, shell, web search, task delegation
18
12
  - **Task Planning** — Break down complex tasks into steps with automatic execution
19
13
  - **Multi-Provider** — Anthropic, OpenAI, Ollama, Groq, OpenRouter, DeepSeek, and others via custom configuration
20
- - **Custom Commands and Skills** — Extend aru via the `.agents/` directory
14
+ - **Custom Commands, Skills, and Agents** — Extend aru via the `.agents/` directory
21
15
  - **MCP Support** — Integration with Model Context Protocol servers
22
16
 
23
17
  ## Quick Start
@@ -62,6 +56,7 @@ That's it — `aru` is available globally after install.
62
56
  | `/mcp` | List available MCP servers and tools |
63
57
  | `/commands` | List custom commands |
64
58
  | `/skills` | List available skills |
59
+ | `/agents` | List custom agents |
65
60
  | `/sessions` | List recent sessions |
66
61
  | `/help` | Show all commands |
67
62
  | `! <command>` | Execute shell commands |
@@ -102,6 +97,7 @@ By default, aru uses **Claude Sonnet 4.6** (Anthropic). You can switch to any su
102
97
  | **OpenAI** | `/model openai/gpt-4o` | `OPENAI_API_KEY` | `pip install "aru-code[openai]"` |
103
98
  | **Groq** | `/model groq/llama-3.3-70b-versatile` | `GROQ_API_KEY` | `pip install "aru-code[groq]"` |
104
99
  | **OpenRouter** | `/model openrouter/deepseek/deepseek-chat-v3-0324` | `OPENROUTER_API_KEY` | `pip install "aru-code[openai]"` |
100
+ | **MiniMax** | `/model openrouter/minimax/minimax-m2.7` | `OPENROUTER_API_KEY` | `pip install "aru-code[openai]"` |
105
101
 
106
102
  To install all providers at once:
107
103
 
@@ -127,9 +123,10 @@ You can set the default provider/model in `aru.json` so you don't need to switch
127
123
 
128
124
  ```json
129
125
  {
130
- "models": {
131
- "default": "openrouter/deepseek/deepseek-chat-v3-0324",
126
+ "default_model": "openrouter/minimax/minimax-m2.7",
127
+ "model_aliases": {
132
128
  "minimax": "openrouter/minimax/minimax-m2.5",
129
+ "minimax-m2.7": "openrouter/minimax/minimax-m2.7",
133
130
  "deepseek-v3": "openrouter/deepseek/deepseek-chat-v3-0324",
134
131
  "sonnet-4-6": "anthropic/claude-sonnet-4-6",
135
132
  "opus-4-6": "anthropic/claude-opus-4-6"
@@ -137,7 +134,7 @@ You can set the default provider/model in `aru.json` so you don't need to switch
137
134
  }
138
135
  ```
139
136
 
140
- The `default` field sets the main model. The other fields are aliases that can be used with `/model <alias>`.
137
+ The `default_model` field sets the main model. The `model_aliases` are shortcuts that can be used with `/model <alias>`.
141
138
 
142
139
  #### Custom providers
143
140
 
@@ -148,12 +145,13 @@ You can configure custom providers with specific token limits:
148
145
  "providers": {
149
146
  "deepseek": {
150
147
  "models": {
151
- "deepseek-chat-v3-0324": {"id": "deepseek-chat-v3-0324", "max_tokens": 16384}
148
+ "deepseek-chat-v3-0324": { "max_tokens": 16384 }
152
149
  }
153
150
  },
154
151
  "openrouter": {
155
152
  "models": {
156
- "minimax/minimax-m2.5": {"id": "minimax/minimax-m2.5", "max_tokens": 65536}
153
+ "minimax/minimax-m2.5": { "max_tokens": 65536 },
154
+ "minimax/minimax-m2.7": { "max_tokens": 131072 }
157
155
  }
158
156
  }
159
157
  }
@@ -162,25 +160,96 @@ You can configure custom providers with specific token limits:
162
160
 
163
161
  ### Permissions (`aru.json`)
164
162
 
165
- The `aru.json` file in the project root controls which shell commands aru can execute **without asking for confirmation**:
163
+ Aru uses a granular permission system where each tool action resolves to one of three outcomes:
164
+
165
+ - **`allow`** — executes without asking
166
+ - **`ask`** — prompts for confirmation (once / always / no)
167
+ - **`deny`** — blocks the action silently
168
+
169
+ Configure permissions per tool category with glob patterns:
166
170
 
167
171
  ```json
168
172
  {
169
173
  "permission": {
170
- "allow": [
171
- "git *",
172
- "npm *",
173
- "pytest *",
174
- "python *",
175
- "uv run pytest *"
176
- ]
174
+ "*": "ask",
175
+ "read": "allow",
176
+ "glob": "allow",
177
+ "grep": "allow",
178
+ "list": "allow",
179
+ "edit": {
180
+ "*": "allow",
181
+ "*.env": "deny"
182
+ },
183
+ "write": {
184
+ "*": "allow",
185
+ "*.env": "deny"
186
+ },
187
+ "bash": {
188
+ "*": "ask",
189
+ "git *": "allow",
190
+ "npm *": "allow",
191
+ "pytest *": "allow",
192
+ "rm -rf *": "deny"
193
+ },
194
+ "web_search": "allow",
195
+ "web_fetch": "allow",
196
+ "delegate_task": "allow"
197
+ }
198
+ }
199
+ ```
200
+
201
+ #### Available categories
202
+
203
+ | Category | Matched against | Default |
204
+ |----------|----------------|---------|
205
+ | `read` | file path | `allow` |
206
+ | `edit` | file path | `ask` |
207
+ | `write` | file path | `ask` |
208
+ | `bash` | command string | safe prefixes = `allow`, rest = `ask` |
209
+ | `glob` | — | `allow` |
210
+ | `grep` | — | `allow` |
211
+ | `list` | — | `allow` |
212
+ | `web_search` | — | `allow` |
213
+ | `web_fetch` | URL | `allow` |
214
+ | `delegate_task` | — | `allow` |
215
+
216
+ #### Rule precedence
217
+
218
+ Rules use **last-match-wins** ordering. Place catch-all `"*"` first, then specific patterns:
219
+
220
+ ```json
221
+ {
222
+ "edit": {
223
+ "*": "allow",
224
+ "*.env": "deny",
225
+ "*.env.example": "allow"
177
226
  }
178
227
  }
179
228
  ```
180
229
 
181
- Each entry is a glob pattern. Any command that doesn't match a listed pattern will prompt for confirmation before executing.
230
+ #### Shorthands
231
+
232
+ ```json
233
+ "permission": "allow"
234
+ ```
235
+ Allows everything (equivalent to `--dangerously-skip-permissions`).
236
+
237
+ ```json
238
+ "permission": { "read": "allow", "edit": "ask" }
239
+ ```
240
+ String value applies to all patterns in that category.
241
+
242
+ #### Defaults
243
+
244
+ Without any `aru.json` config, aru applies safe defaults:
245
+ - Read-only tools (`read`, `glob`, `grep`, `list`) → `allow`
246
+ - Mutating tools (`edit`, `write`) → `ask`
247
+ - Bash → ~40 safe command prefixes auto-allowed (`ls`, `git status`, `grep`, etc.), rest → `ask`
248
+ - Sensitive files (`*.env`, `*.env.*`) → `deny` for read/edit/write (except `*.env.example`)
182
249
 
183
250
  > `aru.json` can also be placed at `.aru/config.json`.
251
+ >
252
+ > A full `aru.json` config reference here: [`aru.json`](./aru.json)
184
253
 
185
254
  ### AGENTS.md
186
255
 
@@ -190,14 +259,98 @@ Place an `AGENTS.md` file in your project root with custom instructions that wil
190
259
 
191
260
  ```
192
261
  .agents/
262
+ ├── agents/ # Custom agents with their own model, tools, and prompt
263
+ │ └── reviewer.md # Usage: /reviewer <args>
193
264
  ├── commands/ # Custom slash commands (filename = command name)
194
265
  │ └── deploy.md # Usage: /deploy <args>
195
266
  └── skills/ # Custom skills/personas
196
- └── review.md # Loaded as additional agent instructions
267
+ └── review/
268
+ └── SKILL.md
197
269
  ```
198
270
 
199
271
  Command files support frontmatter with `description` and the `$INPUT` template variable for arguments.
200
272
 
273
+ ### Custom Agents
274
+
275
+ Custom agents are Markdown files with YAML frontmatter stored in `.agents/agents/`. Each agent runs with its own system prompt, model, and tool set — unlike commands and skills, which reuse the General Agent.
276
+
277
+ ```markdown
278
+ ---
279
+ name: Code Reviewer
280
+ description: Review code for quality, bugs, and best practices
281
+ model: anthropic/claude-sonnet-4-5
282
+ tools: read_file, grep_search, glob_search, code_structure
283
+ max_turns: 15
284
+ mode: primary
285
+ ---
286
+
287
+ You are an expert code reviewer. Analyze code for bugs, security,
288
+ performance, and readability. Do NOT modify files.
289
+ ```
290
+
291
+ #### Frontmatter fields
292
+
293
+ | Field | Required | Description |
294
+ |-------|----------|-------------|
295
+ | `name` | Yes | Display name of the agent |
296
+ | `description` | Yes | When to use this agent (shown in `/agents` and tab completion) |
297
+ | `model` | No | Provider/model reference (e.g., `anthropic/claude-sonnet-4-5`). Defaults to session model |
298
+ | `tools` | No | Comma-separated tool names (allowlist) or JSON object for granular control (e.g., `{"bash": false}`). Defaults to all general tools |
299
+ | `max_turns` | No | Max tool calls before the agent stops. Default: 20 |
300
+ | `mode` | No | `primary` (invocable via `/name`) or `subagent` (only via `delegate_task`). Default: `primary` |
301
+ | `permission` | No | Permission overrides (same format as `aru.json` permission section). Replaces global rules for specified categories while the agent runs |
302
+
303
+ #### Invocation
304
+
305
+ ```
306
+ aru> /reviewer src/auth.py # invoke by slash + filename (without .md)
307
+ aru> /agents # list all custom agents
308
+ ```
309
+
310
+ #### Discovery paths
311
+
312
+ Agents are discovered from multiple locations (later overrides earlier):
313
+
314
+ 1. `~/.agents/agents/` — global (available in all projects)
315
+ 2. `~/.claude/agents/` — global (Claude Code compatible path)
316
+ 3. `.agents/agents/` — project-local
317
+ 4. `.claude/agents/` — project-local
318
+
319
+ #### Agent-level permissions
320
+
321
+ Agents can override global permission rules. Overrides replace the entire category — unspecified categories inherit from global config.
322
+
323
+ ```markdown
324
+ ---
325
+ name: Code Reviewer
326
+ description: Read-only code reviewer
327
+ permission:
328
+ edit: deny
329
+ write: deny
330
+ bash:
331
+ git diff *: allow
332
+ grep *: allow
333
+ ---
334
+ ```
335
+
336
+ You can also set agent permissions in `aru.json` (overrides frontmatter):
337
+
338
+ ```json
339
+ {
340
+ "agent": {
341
+ "reviewer": {
342
+ "permission": { "edit": "deny", "write": "deny" }
343
+ }
344
+ }
345
+ }
346
+ ```
347
+
348
+ Each agent gets its own isolated "always" memory — approvals during an agent's run don't carry over to the global scope.
349
+
350
+ #### Subagent mode
351
+
352
+ Agents with `mode: subagent` can be referenced by the LLM via `delegate_task(task, agent="name")` but are not directly invocable from the CLI.
353
+
201
354
  ### MCP Support (Model Context Protocol)
202
355
 
203
356
  Aru can load tools from MCP servers. Configure in `.aru/mcp_config.json`:
@@ -255,6 +408,7 @@ aru-code/
255
408
  │ ├── cli.py # Interactive CLI with streaming display
256
409
  │ ├── config.py # Configuration loader (AGENTS.md, .agents/)
257
410
  │ ├── providers.py # Multi-provider LLM abstraction
411
+ │ ├── permissions.py # Granular permission system (allow/ask/deny)
258
412
  │ ├── agents/
259
413
  │ │ ├── planner.py # Planning agent
260
414
  │ │ └── executor.py # Execution agent
@@ -0,0 +1 @@
1
+ __version__ = "0.5.0"