# ssh-config-editor

## ADDED Requirements

### Requirement: Per-host SSH command mode

The SSH config editor SHALL support a per-host `ssh_mode` of `shell` or
`wrapper`. In `shell` mode it issues raw shell commands as today; in `wrapper`
mode it issues fixed verbs (`read`, `backup`, `write`, `restart`, `pull`) so the
key can be bound to an `authorized_keys` forced command. The mode defaults to
`shell` for backward compatibility.

#### Scenario: Wrapper-mode host receives verbs

- **WHEN** a host configured with `ssh_mode = wrapper` has its config read
- **THEN** the editor sends the `read` verb (not a `cat` command)

#### Scenario: Shell-mode host is unchanged

- **WHEN** a host configured with `ssh_mode = shell` (the default) is edited
- **THEN** the editor sends the same `cat`/`cp`/`cat >`/restart commands as before

#### Scenario: Backup precedes write in both modes

- **WHEN** a config is applied
- **THEN** a timestamped backup is taken before the new config is written, and a write failure leaves the backup intact

### Requirement: HuggingFace model pull

The editor SHALL expose a non-blocking endpoint to pull a HuggingFace model
repository onto a host into its models directory, validating the repository id
and streaming progress over the `control_job` channel.

#### Scenario: Valid repo id is accepted and runs as a job

- **WHEN** `POST /api/hosts/:id/pull` is called with a repo id matching `org/name`
- **THEN** the request returns 202 and a `control_job` (jobType `action`, `detail.kind = pull`) reports progress and a terminal status

#### Scenario: Malformed repo id is rejected

- **WHEN** the pull endpoint receives a repo id containing spaces, shell metacharacters, or path traversal
- **THEN** the request is rejected before any SSH command is issued
