# 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