Skip to content
Closed
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
41 changes: 36 additions & 5 deletions packages/coding-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

Diffex is a minimal terminal coding harness. Adapt Diffex to your workflows, not the other way around, without having to fork and modify Diffex internals. Extend it with TypeScript [Extensions](#extensions), [Skills](#skills), [Prompt Templates](#prompt-templates), and [Themes](#themes). Put your extensions, skills, prompt templates, and themes in [Diffex Packages](#diffex-packages) and share them with others via npm or git.

Diffex ships with powerful defaults, including session-scoped sub-agents, but skips features like plan mode. You can ask Diffex to build other workflows or install a third party Diffex package that matches them.
Diffex ships with powerful defaults, including a native read-only plan mode and session-scoped sub-agents. You can build other workflows or install a third-party Diffex package that provides them.

Diffex runs in four modes: interactive, print or JSON, RPC for process integration, and an SDK for embedding in your own apps.

Expand All @@ -39,6 +39,7 @@ Example upstream `pi-mono` work sessions are published here:
- [Quick Start](#quick-start)
- [Providers & Models](#providers--models)
- [Interactive Mode](#interactive-mode)
- [Plan Mode](#plan-mode)
- [Editor](#editor)
- [Commands](#commands)
- [Keyboard Shortcuts](#keyboard-shortcuts)
Expand Down Expand Up @@ -147,10 +148,32 @@ The interface from top to bottom:
- **Startup header** - Shows shortcuts (`/hotkeys` for all), loaded AGENTS.md files, prompt templates, skills, and extensions
- **Messages** - Your messages, assistant responses, tool calls and results, notifications, errors, and extension UI
- **Editor** - Where you type; border color indicates thinking level
- **Footer** - Working directory, session name, total token/cache usage (`↑` input, `↓` output, `R` cache read, `W` cache write, `CH` latest cache hit rate), cost, context usage, current model. Totals include assistant responses, usage reported by tools, and summary generation.
- **Footer** - The built-in footer keeps the active profile, routing mode, and harness visible above the current model, thinking level, and context usage.

The editor can be temporarily replaced by other UI, like built-in `/settings` or custom UI from extensions (e.g., a Q&A tool that lets the user answer model questions in a structured format). [Extensions](#extensions) can also replace the editor, add widgets above/below it, a status line, custom footer, or overlays.

### Plan Mode

Run `diffex --plan` to start an interactive session in plan mode, or use `/plan [on|off]` while Diffex is idle.
Plan mode exposes `submit_plan` and the canonical subset of `read`, `grep`, `find`, and `ls` permitted by caller restrictions and the active task profile.
The agent can inspect the repository, but it cannot run commands, edit files, or call extension and SDK tools.
`submit_plan` is intrinsic to plan mode and remains available even when caller tool filters disable every inspection tool.
Automatic task-profile routing pauses for planning prompts.
In automatic mode, choosing Implement routes every accepted task before execution, even when a harness is already active.
The router may keep the active harness for a continuation, reuse a related harness, or switch to a newly selected task harness.
Diffex asks which profile should govern implementation only when the router finds a high-confidence ambiguity among specialized profiles.
The chooser shows each option's description, safeguards, and tool-policy summary.
The choice determines the implementation profile's expertise, safeguards, and tool access.
The recommended option receives initial focus but is not selected automatically.
Canceling the choice leaves the accepted implementation pending; use `/plan` to retry.
A malformed, low-confidence, or failed route also leaves the accepted implementation pending instead of silently falling back to another profile.
A pinned profile bypasses automatic routing and implements the plan in place.
Pin a profile before planning when its guardrails must apply during planning itself.

Submitting a plan ends the planning turn and stores the plan in the session until you implement or discard it.
Pending plans and collaboration-mode changes survive session resume and tree navigation.
The `--plan` flag is supported only in interactive mode.

### Editor

| Feature | How |
Expand All @@ -174,6 +197,7 @@ Type `/` in the editor to trigger commands. [Extensions](#extensions) can regist
| [`/llama`](docs/llama-cpp.md) | Download, load, and unload llama.cpp router models |
| `/model` | Switch models |
| `/scoped-models` | Enable/disable models for Ctrl+P cycling |
| `/plan [on\|off]` | Toggle plan mode, set it explicitly, or reopen a pending plan |
| `/settings` | Thinking level, theme, message delivery, transport |
| `/resume` | Pick from previous sessions |
| `/new` | Start a new session |
Expand Down Expand Up @@ -384,7 +408,7 @@ The default export can also be `async`. Diffex waits for async extension factori

**What's possible:**
- Custom tools (or replace built-in tools entirely)
- Alternative sub-agent workflows and plan mode
- Alternative sub-agent, planning, and custom workflows
- Custom compaction and summarization
- Permission gates and path protection
- Custom editors and UI components
Expand Down Expand Up @@ -501,7 +525,7 @@ Diffex is aggressively extensible so it doesn't have to dictate your workflow. F

**No permission popups.** Run in a container, or build your own confirmation flow with [extensions](#extensions) inline with your environment and security requirements.

**No plan mode.** The built-in `update_plan` tool is only a lightweight progress checklist. For approval workflows, read-only planning phases, or richer planning modes, write plans to files, build an [extension](#extensions), or install a package.
**Native plan mode stays read-only.** It uses a fixed planning tool set and requires explicit resolution before implementation begins.

**No persistent built-in to-dos.** Use a TODO.md file, or build your own with [extensions](#extensions).

Expand Down Expand Up @@ -544,8 +568,11 @@ diffex config # Enable/disable package resources
| `-p`, `--print` | Print response and exit |
| `--mode json` | Output all events as JSON lines (see [docs/json.md](docs/json.md)) |
| `--mode rpc` | RPC mode for process integration (see [docs/rpc.md](docs/rpc.md)) |
| `--plan` | Start interactive mode with native plan mode active |
| `--export <in> [out]` | Export session to HTML |

Diffex rejects `--plan` with `-p`, `--mode json`, and `--mode rpc` because those hosts cannot resolve a submitted plan interactively.

In print mode, Diffex also reads piped stdin and merges it into the initial prompt:

```bash
Expand Down Expand Up @@ -582,9 +609,10 @@ cat README.md | diffex -p "Summarize this text"
| `--tools <list>`, `-t <list>` | Allowlist specific tool names across built-in, extension, and custom tools |
| `--exclude-tools <list>`, `-xt <list>` | Disable specific tool names across built-in, extension, and custom tools |
| `--no-builtin-tools`, `-nbt` | Disable built-in tools by default but keep extension/custom tools enabled |
| `--no-tools`, `-nt` | Disable all tools by default |
| `--no-tools`, `-nt` | Disable all normal-mode tools and plan-mode inspection tools by default |

Available built-in tools: `read`, `bash`, `edit`, `write`, `update_plan`, `grep`, `find`, `ls`
Tool allowlists and denylists also constrain plan-mode inspection tools, but the intrinsic `submit_plan` tool remains available in plan mode.

### Resource Options

Expand Down Expand Up @@ -631,6 +659,9 @@ diffex @code.ts @test.ts "Review these files"
# Interactive with initial prompt
diffex "List all .ts files in src/"

# Interactive read-only planning
diffex --plan "Design the implementation before changing anything"

# Non-interactive
diffex -p "Summarize this codebase"

Expand Down
14 changes: 8 additions & 6 deletions packages/coding-agent/docs/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,7 @@ Register a keyboard shortcut. See [keybindings.md](keybindings.md) for the short

```typescript
diffex.registerShortcut("ctrl+shift+p", {
description: "Toggle plan mode",
description: "Toggle project summary",
handler: async (ctx) => {
ctx.ui.notify("Toggled!");
},
Expand All @@ -1622,15 +1622,15 @@ diffex.registerShortcut("ctrl+shift+p", {
Register a CLI flag.

```typescript
diffex.registerFlag("plan", {
description: "Start in plan mode",
diffex.registerFlag("audit", {
description: "Enable additional audit checks",
type: "boolean",
default: false,
});

// Check value
if (diffex.getFlag("plan")) {
// Plan mode enabled
if (diffex.getFlag("audit")) {
// Additional audit checks enabled
}
```

Expand Down Expand Up @@ -2048,6 +2048,8 @@ diffex.registerTool({

Extensions can override built-in tools (`read`, `bash`, `edit`, `write`, `update_plan`, `grep`, `find`, `ls`) by registering a tool with the same name. Interactive mode displays a warning when this happens.

Native plan mode is an exception: while it is active, extension and SDK tools cannot override the canonical `read`, `grep`, `find`, `ls`, or `submit_plan` tool identities.

```bash
# Extension's read tool replaces built-in read
diffex -e ./tool-override.ts
Expand Down Expand Up @@ -2960,7 +2962,7 @@ All examples in [examples/extensions/](../examples/extensions/).
| `timed-confirm.ts` | Dialogs with timeout | `ui.confirm` with timeout/signal |
| `mac-system-theme.ts` | Auto-switch theme | `setTheme`, `exec` |
| **Complex Extensions** |||
| `plan-mode/` | Full plan mode implementation | All event types, `registerCommand`, `registerShortcut`, `registerFlag`, `setStatus`, `setWidget`, `sendMessage`, `setActiveTools` |
| `plan-mode/` | Legacy example that is incompatible with native plan mode | Historical extension APIs only; do not load it |
| `preset.ts` | Saveable presets (model, tools, thinking) | `registerCommand`, `registerShortcut`, `registerFlag`, `setModel`, `setActiveTools`, `setThinkingLevel`, `appendEntry` |
| `tools.ts` | Toggle tools on/off UI | `registerCommand`, `setActiveTools`, `SettingsList`, session events |
| **Remote & Sandbox** |||
Expand Down
19 changes: 14 additions & 5 deletions packages/coding-agent/docs/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,34 @@
diffex --mode json "Your prompt"
```

Outputs all session events as JSON lines to stdout. Useful for integrating Diffex into other tools or custom UIs.
Outputs the session events supported by the JSON wire protocol as JSON lines to stdout.
This mode is useful for integrating Diffex into other tools or custom UIs.

## Event Types

Wire events use `JsonAgentSessionEvent`. It matches
[`AgentSessionEvent`](https://github.com/diffexai/diffex/blob/main/packages/coding-agent/src/core/agent-session.ts)
except that streaming message updates omit cumulative snapshots:
Wire events use `JsonAgentSessionEvent`, which matches [`AgentSessionEvent`](https://github.com/diffexai/diffex/blob/main/packages/coding-agent/src/core/agent-session.ts) except for plan-only lifecycle events and cumulative streaming snapshots.

```typescript
type WithoutPartial<T> = T extends { partial: unknown } ? Omit<T, "partial"> : T;

type JsonAgentSessionEvent =
| Exclude<AgentSessionEvent, { type: "message_update" }>
| Exclude<
AgentSessionEvent,
{
type:
| "message_update"
| "collaboration_mode_changed"
| "plan_submitted"
| "plan_resolved";
}
>
| {
type: "message_update";
assistantMessageEvent: WithoutPartial<AssistantMessageEvent>;
};
```

The plan-only `collaboration_mode_changed`, `plan_submitted`, and `plan_resolved` events are available to direct `AgentSession` subscribers but are omitted because JSON mode cannot host plan resolution.
`queue_update` emits the full pending steering and follow-up queues whenever they change. `compaction_start` and `compaction_end` cover both manual and automatic compaction.

Other base events come from
Expand Down
Loading