# Clone tool: design Date: 2026-10-19. Status: implemented (2026-10-19). ## Goal Ask the assistant to clone a public repository ("clone this repo: https://github.com/owner/repo") and have it land in the right folder of `~/Programming/GIT`: `GITHUB/`, `GITLAB/`, `FORGE/`, or a folder already approved for that host. Public repositories only, plain `git clone`, no SSH aliases or keys. The assistant must not decide two things alone: a host with no folder yet, and a repository that is already cloned. Both are asked, with a concrete action, never a bare "skip". ## Tool `examples/tools/clone.toml`, installed to `~/.config/desktop-assistant/tools/` like the others. No change to `assistant.py`. ```toml command = ["clone.sh", "{url}", "{to}", "{update}"] timeout = 300 ``` - `url`: the repository URL. - `to`: only when the user approved a new host folder; the folder name. - `update`: `1` to pull an existing clone. `examples/tools/clone.sh`: - Parses `https://host/owner/repo` and `git@host:owner/repo` alike; `repo` is the last path segment with a trailing `/` and a `.git` suffix removed, and `owner` is the segment before it (a nested group keeps only its last segment). `host`, `repo` and `owner` are validated as plain names, so none can escape the tree. - Resolves `host -> folder` from the mapping file. Absent, it is seeded with `github.com -> GITHUB`, `gitlab.com -> GITLAB`, `forge.slackware.nl -> FORGE`. - Target is `//-` (`CLONE_ROOT`, default `~/Programming/GIT`). The name is just `` when the URL carries no owner (`git@host:repo.git`) or when `owner` and `repo` are the same (`firefly-iii/firefly-iii`), so a generic repo name like `wallpapers` becomes `evgen2571-wallpapers` while a self-named one is not doubled. - Known host, target free: `git clone` and report it. No question. - Unknown host: prints the folder to offer (hostname without its last label, uppercased: `codeberg.org -> CODEBERG`) and does nothing. - Target exists: prints "already cloned" and does nothing. With `update=1`, runs `git pull --ff-only` and reports the result; a diverged clone is an error, not a merge. - A `to` given for an unknown host clones there and appends `hostfolder` to the mapping, so that host is known from then on. An existing mapping is never duplicated or overwritten. ## Mapping file `~/.config/desktop-assistant/clone-hosts` (`CLONE_MAP`), one `hostfolder` line per host, user-editable. It lives outside the tool directory so reinstalling the tools does not lose it, and the file is the single source of truth: nothing is hardcoded in the script beyond the seed. ## Check `test-clone.sh`: a scratch `CLONE_ROOT` and `CLONE_MAP`, and a `git` stub on `PATH` that records its argv and creates the target, so no network and no real tree. Covers seeding, clone argv, trailing slash and `.git`, the unknown-host message, the approved folder being remembered and used on the next clone without a question, no duplicate map line, the already-cloned message, the update argv, and the refused inputs. Live, against the running model: ask for a known host and an unknown host, accept the offered folder, ask for the same host again (must ask nothing), then ask for an existing repo (must offer an update, never a second clone). ## Not included Private repositories (no credentials), clone depth or branches, and opening the clone in an editor or agent after it lands.