Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ cost estimates, and a much more robust terminal UI.
OpenAI/DeepSeek/Kimi/Gemini automatic caches keep hitting.
- **`/cost`** and cost estimates in the per-turn line, `/tokens`, the bottom bar and JSON output; prices are
approximate and overridable under `pricing:` in `config.yaml`.
- **More slash commands**, matching the CLI: `/permissions allow|deny|set|reset`, `/sessions`, `/hooks`, `/trust`,
`/untrust`, `/exit`.
- **`--mode` for `devorch` / `devorch chat`, and `--dangerously-skip-permissions`** on every entry point (same as
`--mode auto`: no prompts; dangerous-command blocks and deny rules still apply).
- **Input surface**: open input box with a coloured mode label, `Shift+Tab` mode cycling, `Ctrl+J` newline, a
width-aware placeholder and bottom bar, context-usage gauge.

Expand All @@ -42,6 +46,7 @@ cost estimates, and a much more robust terminal UI.
- The bottom toolbar re-ran `git` on every keystroke; it is now cached.
- The bottom toolbar rendered as a bright reversed bar, and was clipped on narrow terminals, hiding the mode.
- Saving config no longer drops a `pricing:` section.
- The slash-command dropdown vanished when a command was fully typed (`/cost`, `/models`).

### Changed
- CI runs on pull requests only.
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,23 @@ With `--output json` stdout contains a single JSON object (`result`, `is_error`,
on failure, so it is safe to use in scripts and CI. `stream-json` emits `tool_call` events as they happen
followed by a final `result` event. Available on `ask` and `run`.

All non-interactive commands support `--provider`, `--model`, `--mode`, `--mcp`, and `--no-mcp`.
All non-interactive commands support `--provider`, `--model`, `--mode`, `--mcp`, `--no-mcp` and
`--dangerously-skip-permissions`. `devorch` / `devorch chat` take `--mode` and `--dangerously-skip-permissions`
too, so you can start the REPL in a given mode.

### Skipping permission prompts

```bash
devorch --dangerously-skip-permissions # start the REPL in AUTO mode
devorch ask --dangerously-skip-permissions "run the tests and fix failures"
devorch --mode plan # or start in plan / ask mode
```

`--dangerously-skip-permissions` is the same as `--mode auto`: **no prompts at all**, so the agent can edit files
and run commands unasked. It is not a full bypass: the built-in dangerous-command blocks (`rm -rf *`, `sudo`, ...)
and your own `deny` rules still apply, and project hooks still run. It conflicts with `--mode ask|plan`, and it
overrides a project's `default_mode`. In the REPL, `/auto` and `/ask` switch the same behaviour on and off, and
`/permissions allow --session shell pytest*` skips prompts for just one kind of command.

## All Slash Commands

Expand Down Expand Up @@ -484,7 +500,12 @@ All non-interactive commands support `--provider`, `--model`, `--mode`, `--mcp`,
| `/mcp start <name>` | Reconnect a server from config |
| `/mcp stop <name>` | Disconnect a server and remove its tools |
| `/config` | Show configuration settings |
| `/permissions` | Show and manage tool permission settings |
| `/permissions` | Show permissions; change them with `/permissions allow\|deny [--session] <tool> <pattern>`, `set <tool> <allow\|deny\|ask>`, `reset` |
| `/sessions` | `list [n]`, `show <id>`, `delete <id>` (resume with `devorch --resume <id>`) |
| `/hooks` | Show active hooks and whether project hooks are trusted |
| `/trust` / `/untrust` | Trust (or stop trusting) this project's `.devorch` settings and hooks |
| `/cost` | Estimated session cost per model |
| `/exit` | Exit DevOrch (also `exit`, `quit`, or Ctrl+C twice) |
| `/tasks` | Show multi-step task list and execution progress |

## Configuration
Expand Down
23 changes: 21 additions & 2 deletions cli/commands/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,27 @@ def print_project_notices(settings) -> None:
print_warning(notice)


def resolve_mode(mode_str: str | None, default: AgentMode = AgentMode.AUTO) -> AgentMode:
"""Parse and validate a mode string, exit with error on bad input."""
SKIP_PERMISSIONS_HELP = (
"Skip every permission prompt (same as --mode auto). Built-in dangerous-command blocks and "
"your deny rules still apply."
)


def resolve_mode(
mode_str: str | None,
default: AgentMode = AgentMode.AUTO,
skip_permissions: bool = False,
) -> AgentMode:
"""Parse and validate a mode string, exit with error on bad input.

``skip_permissions`` (``--dangerously-skip-permissions``) forces AUTO, which never prompts; deny
rules and the built-in dangerous-command blocks are still enforced by the executor.
"""
if skip_permissions:
if mode_str and mode_str.lower() != "auto":
print_error(f"--dangerously-skip-permissions conflicts with --mode {mode_str}")
raise typer.Exit(1)
return AgentMode.AUTO
if not mode_str:
project_mode = load_project_mode()
return AgentMode(project_mode) if project_mode else default
Expand Down
6 changes: 5 additions & 1 deletion cli/commands/ask.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from cli.commands._output import configure_output, run_with_output, validate_format
from cli.commands._shared import (
SKIP_PERMISSIONS_HELP,
build_agent,
build_tools,
console,
Expand All @@ -30,6 +31,9 @@ def ask(
mode: str = typer.Option(None, "--mode", help="Execution mode: ask, auto, plan"),
no_mcp: bool = typer.Option(False, "--no-mcp", help="Disable all MCP servers for this run"),
mcp: list[str] = typer.Option(None, "--mcp", help="Use only these MCP servers (repeatable)"),
skip_permissions: bool = typer.Option(
False, "--dangerously-skip-permissions", help=SKIP_PERMISSIONS_HELP
),
output: str = typer.Option(
"text", "--output", "-o", help="Output format: text, json, stream-json"
),
Expand All @@ -56,7 +60,7 @@ def ask(

llm = create_provider(provider, model, settings)
tools = build_tools(settings, no_mcp=no_mcp, mcp_only=mcp or None)
agent_mode = resolve_mode(mode, default=AgentMode.AUTO)
agent_mode = resolve_mode(mode, default=AgentMode.AUTO, skip_permissions=skip_permissions)
memory_ctx = MemoryManager().get_context_prompt()
project_ctx = ProjectContextLoader().load()
project_prompt = project_ctx.to_system_prompt_block() if project_ctx else ""
Expand Down
6 changes: 5 additions & 1 deletion cli/commands/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import typer

from cli.commands._shared import (
SKIP_PERMISSIONS_HELP,
build_agent,
build_tools,
console,
Expand All @@ -23,6 +24,9 @@ def edit(
mode: str = typer.Option("auto", "--mode", help="Execution mode: ask, auto, plan"),
no_mcp: bool = typer.Option(False, "--no-mcp", help="Disable all MCP servers for this run"),
mcp: list[str] = typer.Option(None, "--mcp", help="Use only these MCP servers (repeatable)"),
skip_permissions: bool = typer.Option(
False, "--dangerously-skip-permissions", help=SKIP_PERMISSIONS_HELP
),
):
"""
Edit a specific file using an AI instruction.
Expand All @@ -42,7 +46,7 @@ def edit(
llm = create_provider(provider, model, settings)
# edit only needs file-oriented tools — no terminal/task tools
tools = build_tools(settings, include_terminal=False, no_mcp=no_mcp, mcp_only=mcp or None)
agent_mode = resolve_mode(mode)
agent_mode = resolve_mode(mode, skip_permissions=skip_permissions)
memory_ctx = MemoryManager().get_context_prompt()
agent = build_agent(llm, tools, memory_ctx, agent_mode, pricing=settings.pricing)

Expand Down
6 changes: 5 additions & 1 deletion cli/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from cli.commands._output import configure_output, run_with_output, validate_format
from cli.commands._shared import (
SKIP_PERMISSIONS_HELP,
build_agent,
build_tools,
console,
Expand All @@ -28,6 +29,9 @@ def run(
),
no_mcp: bool = typer.Option(False, "--no-mcp", help="Disable all MCP servers for this run"),
mcp: list[str] = typer.Option(None, "--mcp", help="Use only these MCP servers (repeatable)"),
skip_permissions: bool = typer.Option(
False, "--dangerously-skip-permissions", help=SKIP_PERMISSIONS_HELP
),
output: str = typer.Option(
"text", "--output", "-o", help="Output format: text, json, stream-json"
),
Expand Down Expand Up @@ -62,7 +66,7 @@ def run(
final_prompt = render_prompt(skill_data, extra)

tools = build_tools(settings, no_mcp=no_mcp, mcp_only=mcp or None)
agent_mode = resolve_mode(mode)
agent_mode = resolve_mode(mode, skip_permissions=skip_permissions)
memory_ctx = MemoryManager().get_context_prompt()
project_ctx = ProjectContextLoader().load()
project_prompt = project_ctx.to_system_prompt_block() if project_ctx else ""
Expand Down
7 changes: 6 additions & 1 deletion cli/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@
"/clear": "Clear conversation history (saves accomplishments to project memory)",
"/session": "Show current session ID, model, and message count",
"/config": "Show configuration settings and provider status",
"/permissions": "Show and manage tool permission settings",
"/permissions": "Show or change permissions (/permissions allow|deny|set|reset)",
"/sessions": "List, show or delete chat sessions (/sessions list|show <id>|delete <id>)",
"/hooks": "Show active hooks and whether project hooks are trusted",
"/trust": "Trust this project's .devorch settings and hooks (MCP, allow rules, hooks)",
"/untrust": "Revoke trust for this project's .devorch files",
"/exit": "Exit DevOrch (also: exit, quit, Ctrl+C twice)",
"/compact": "Summarize and compact conversation history to save tokens",
"/models": "Search, browse, and switch models (interactive 15/page pagination)",
"/model": "Switch model directly (/model <name>) or open interactive search",
Expand Down
Loading
Loading