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
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ playwright-report/
test-results/
package-lock.json
Cargo.lock
packages/renderer-extension/src/settings/windows-update.preview.html
27 changes: 21 additions & 6 deletions docs/harness-command-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ Choose a stable command ID and descriptor:

```ts
{
id: "pi.compact",
invocation: "/compact",
label: "Compact context",
id: "dsh.plan",
invocation: "/plan",
label: "Plan mode",
argumentMode: "text",
}
```
Expand Down Expand Up @@ -41,19 +41,22 @@ For commands with visible progress, decide explicitly whether they need:

## 4. Reuse Host and Renderer routing

The shared command catalog and Host command RPC should not need command-specific branches. The Renderer should consume the catalog and execute by command ID through the Composer's independent Harness Commands button and popover.
The shared command catalog and Host command RPC should not need command-specific branches. The Renderer should consume the catalog through the Composer's independent Harness Commands button and popover. Selecting an argument-free command executes it directly; selecting a text command prefixes its invocation in the current editor and leaves the draft and attachments in place for the ordinary submit path.

The command button belongs to the active external Harness controls, near the Composer's left-side actions. It MUST remain outside the Codex React-managed Slash command list; the independent popover owns its own focus, keyboard navigation, positioning, and scrolling.

Only add Renderer-specific code when the command needs a new presentation or interaction.

External Harness text Turns do not accept image input. Host rejects those submissions before Adapter execution instead of silently dropping attachments.

## 5. Add focused tests

At minimum, cover:

- command appears in the owning Adapter catalog;
- unknown command is rejected;
- invalid arguments are rejected;
- image-bearing External Harness Turns fail before command execution;
- busy Session is rejected;
- native operation is called with the expected payload;
- success, failure, and cancellation are projected correctly;
Expand All @@ -71,20 +74,28 @@ git diff --check

For native RPC changes, also verify the request and event sequence against the real Harness when available.

## Current examples: Pi, Grok, and Claude commands
## Current examples: Pi, Grok, Claude, and DeepSeek commands

```text
Renderer command catalog
-> Composer Harness Commands button
-> independent command popover
-> Host command/execute
-> argumentMode none: fixed Host command/execute
argumentMode text: prefix the Composer, then ordinary turn/start
-> current Host catalog validation
-> owning Adapter
Pi: native { type: "compact" }
Grok: x.ai/compact_conversation { sessionId, userContext? }
Claude: dedicated transport
/compact context compaction
/init generate CLAUDE.md
/recap one-line session recap
DeepSeek: commands/list for the current Native Session
/compact
/dsh-goal [<objective>|clear|edit <objective>|pause|resume]
-> native /goal
/plan [off|message]
-> commands/execute { agentId, line }
-> existing Host Item projection
-> temporary Turn cleanup unless the command requires persistence
```
Expand All @@ -94,6 +105,10 @@ maps it to custom summarization instructions. `/init` and `/recap` take no
arguments. These commands invoke Harness-native operations and must not be
submitted as Host text Turns.

DeepSeek is dynamic rather than a fixed catalog. The Adapter preserves the relative order of the current Session's native `commands/list` response and maps only valid `compact`, `goal`, and `plan` descriptors to stable codexhost IDs. Missing or incompatible entries disappear; malformed catalogs fail explicitly. Native `feedback` conflicts with Codex Desktop's built-in command of the same name and is not exposed. Native `permission` and `export`, the Client-side `/model`, and unknown future commands are also not exposed through this surface.

The public `/dsh-goal` invocation avoids Codex Desktop's built-in `/goal` command and maps only inside the Adapter to native DSH `/goal`. `/dsh-goal` and `/plan` accept text arguments only. DSH remains the owner of goal and plan state and any model-visible follow-up.

## Boundaries

- The Adapter owns Harness-specific semantics.
Expand Down
58 changes: 57 additions & 1 deletion openspec/specs/harness-command-capabilities/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ A Harness Adapter MUST publish a command catalog containing stable command IDs,
- **THEN** the catalog contains the registered `claude.init` and `claude.recap` commands
- **AND** both commands declare their invocations and argument mode `none`

#### Scenario: DeepSeek exposes only reviewed native commands

- **WHEN** a DeepSeek Session lists Harness commands
- **THEN** the Adapter reads that Session's current native `commands/list` catalog
- **AND** it maps valid advertised entries only to `dsh.compact`, `dsh.goal`, and `dsh.plan`, preserving their native relative order
- **AND** the mapped commands declare `/compact` with argument mode `none`, plus `/dsh-goal` and `/plan` with argument mode `text`
- **AND** `/dsh-goal` maps to native DSH `/goal` without entering Codex Desktop's built-in `/goal` flow
- **AND** it does not expose native `/feedback` because Codex Desktop owns a conflicting built-in command

#### Scenario: DeepSeek native catalog is missing or malformed

- **WHEN** a reviewed command is absent, has an incompatible input descriptor, or the native catalog contains invalid fields, duplicate names, or invalid descriptions
- **THEN** an absent or incompatible command is omitted, while a malformed catalog fails with a protocol error and exposes no partial result
- **AND** codexhost MUST NOT substitute a fixed catalog

#### Scenario: DeepSeek control and future commands remain excluded

- **WHEN** DSH advertises `permission`, `export`, or an unknown future command, or the Client contributes `/model`
- **THEN** none is exposed as a normal Harness command
- **AND** Permission Mode and Model selection remain on their existing first-class controls

### Requirement: Host validates and routes registered commands

The Host MUST obtain the current Harness command catalog before execution, MUST reject unknown command IDs, and MUST validate arguments at the command boundary. The Host MUST NOT provide an arbitrary native RPC passthrough.
Expand All @@ -38,6 +59,18 @@ The Host MUST obtain the current Harness command catalog before execution, MUST
- **THEN** the Host rejects the request
- **AND** no native Harness operation is started

#### Scenario: Unmatched slash input fails closed

- **WHEN** an external Thread submits slash-shaped text that matches no command in its current catalog
- **THEN** Host rejects the submission as an unavailable Harness command
- **AND** it does not send that text as a normal model Prompt or attempt an arbitrary native command

#### Scenario: External command image input fails closed

- **WHEN** an External Harness command submission carries `image` or `localImage` inputs
- **THEN** Host rejects the submission before Adapter execution
- **AND** it does not silently drop the images or submit the remaining text

### Requirement: Native command semantics remain inside the owning Adapter

The Adapter MUST translate a registered command into the Harness-native operation and MUST translate native success, failure, cancellation, and busy states into Host-facing results or events. Shared layers MUST NOT contain Harness-specific RPC details.
Expand All @@ -60,16 +93,39 @@ The Adapter MUST translate a registered command into the Harness-native operatio
- **THEN** the Claude Adapter calls the dedicated init or recap transport
- **AND** it does not submit those invocations as Host text Turns

#### Scenario: DeepSeek commands use the native command Remote

- **WHEN** a reviewed DeepSeek command is executed
- **THEN** the Adapter rechecks the current Session catalog and calls native `commands/execute` with the exact command line and cancellation signal
- **AND** codexhost does not reproduce the command's state changes or send it as a normal Prompt

### Requirement: Command UI and lifecycle follow Host contracts

A command MAY be discovered by the Renderer through the Host command catalog. The Renderer SHALL present discovered commands through an independent Composer Harness Commands control rather than mutating the Codex-native Slash command list. Its popover SHALL own its layout, scrolling, focus, and keyboard navigation. If execution produces visible lifecycle events, those events MUST use existing Host projection contracts. Temporary command projection Turns MUST NOT be persisted as ordinary conversation history unless the command explicitly requires persistence.

#### Scenario: Text command selection claims the Composer

- **WHEN** the user selects a command with argument mode `text` from the Harness Commands popover
- **THEN** Renderer prefixes its invocation and one space to the current Composer editor while preserving the existing draft and attachments
- **AND** the command uses the ordinary Composer submission path instead of executing a bare invocation immediately

#### Scenario: Argument-free command selection executes directly

- **WHEN** the user selects a command with argument mode `none`
- **THEN** Renderer executes that registered command directly through the fixed Host command route

#### Scenario: Manual compaction is projected without a user Turn

- **WHEN** Pi or Claude Code emits native compaction start and end events for their compact command
- **WHEN** Pi, Grok, Claude Code, or DeepSeek emits native compaction start and end events for its compact command
- **THEN** codexhost projects the standard context-compaction UI lifecycle
- **AND** the temporary command Turn is not added to ordinary Thread history

#### Scenario: DeepSeek command result text uses existing projection

- **WHEN** DeepSeek `/goal` or `/plan` returns native success or error text
- **THEN** codexhost projects the text through the existing Command Execution Item and completes the temporary Turn with the native outcome
- **AND** native log-only command lifecycle records do not become ordinary conversation Turns

### Requirement: Commands remain isolated by Harness ownership

The Renderer and Host MUST expose only commands belonging to the current external Harness Thread. A command registered by one Harness MUST NOT appear or execute in another Harness Thread.
Expand Down
Loading
Loading