diff --git a/docs/design-import-gaps.md b/docs/design-import-gaps.md
index 03f34a8..b873f14 100644
--- a/docs/design-import-gaps.md
+++ b/docs/design-import-gaps.md
@@ -510,7 +510,7 @@ field cannot be removed and stays as a permanently refused member; `SyncEndpoint
| Org chip `dodotech / platform` | contracts + server | An *organisation* above teams, which does not exist — `VaultSummary.TeamId` is no longer always null since M3, but a team is not an org and there is exactly one tenant per deployment. | The vault's own name, and the account this machine is enrolled as. Team names are on the VAULTS screen, where they are about something. |
| `SYNCED` dot, always green | client-app | Nothing — the design's claim is simply unconditional. | Green **only** when a connection is held, the last sync pass actually reached the server, and the outbox is empty; otherwise `UNREACHABLE`, the count of changes still waiting, or `OFFLINE`. Holding an `IVaultServer` proves a sign-in once succeeded and nothing more, so a laptop whose lid has been shut all afternoon still has one — reachability comes from the outcome of the last pass. A permanently green light is the same as no light. |
| `VAULT SYNCED 11:02` | client-session | `StoredSyncState.LastPulledAt`/`LastPushedAt` are persisted, but `VaultSession` exposes the store as `internal`. A property away. | Omitted. The one honest sync fact — the outbox depth — is in the titlebar and the status bar. |
-| `⌘K` command palette running commands | client-domain | A snippet or saved-command item type (`SyncEntityType.Snippet = 8` is reserved). | Ctrl+K opens a real host search that connects on Enter. The box says "search hosts", not "search hosts · run command". |
+| `⌘K` command palette running commands | client-domain | A snippet or saved-command item type (`SyncEntityType.Snippet = 8` is reserved). | Ctrl+K opens a real host search that connects on Enter, and reads a typed `user@host[:port]` as a machine to connect to with a password, without saving it. The box says "search hosts, or type user@host", not "search hosts · run command". |
| Status bar `· via bastion-eu` | client-ssh | Jump-host execution. See below. | Omitted. |
| Status bar port forwards | client-ssh | — | **Shipped** on the session status bar as a count of listening forwards; the ports themselves are in the session sidebar. |
| Status bar `sftp · 2 transfers` | client-app | Nothing now — file transfer is built. What is missing is the count reaching the status bar, which is a screen away from where the queue lives. | Omitted from the status bar. The queue itself is on the FILES screen, with a row per transfer. |
diff --git a/docs/manual-checks.md b/docs/manual-checks.md
index d49fc09..61a3d7e 100644
--- a/docs/manual-checks.md
+++ b/docs/manual-checks.md
@@ -1388,6 +1388,39 @@ Ctrl+K, then click a result with the mouse rather than pressing Enter.
**Pass:** the palette closes and the connection starts.
+### 7.10a Connecting to a machine that is not saved
+
+Ctrl+K, type `user@host` for a reachable machine that is **not** on HOSTS, press Enter, type its password and
+press Enter again. Do it once against a machine whose host key this vault has never seen.
+
+**Pass:** the palette asks for the password in place, with the caret already in the box. On the second Enter
+it closes, a tab named `user@host` opens, and the fingerprint card asks about the key; approving it connects.
+Afterwards HOSTS has nothing new on it, and the connection log has an entry for `user@host:22`. Escape from
+the password box goes back to the address with what was typed still in it.
+
+**Failure means:** a new row on HOSTS is the palette saving what it promised not to. A tab that fails with
+"authentication failed" for a password known to be right is worth comparing against the phone's CONNECT TO A
+MACHINE box, which takes the same path — `VaultViewModel.ConnectToEndpointAsync` — so a difference between
+the two is in how the palette hands the password over, not in the connection. The headless half of this is
+`QuickConnectTests`; what it cannot do is dial.
+
+### 7.10b Pressing Terminal with nothing open asks what to connect to
+
+Close every terminal tab, then press **Terminal** on the rail.
+
+**Pass:** the terminal's frame holds a prompt — `connect to:` with the caret already on it, so typing works
+without a click. Type part of a saved host's name: the matching hosts appear under the line, Tab completes to
+the first, and Enter connects to it — asking `user@host:port's password:` first only if that host has no key
+or saved password. Type `user@host` for a machine that is not saved instead: Enter asks for its password, and
+the second Enter opens a tab for it. Escape steps back from the password to the name. Afterwards HOSTS has
+nothing new on it, and no credential was saved — even with "remember" ticked in a host's drawer earlier.
+
+**Failure means:** a prompt that needs a click before it takes typing is the terminal's WebView still holding
+the native keyboard focus — see `NativeKeyboardFocus`, which `ConnectPrompt.TakeKeyboard` calls. Anything drawn
+*under* a blank rectangle is the occlusion rule broken: the prompt may only show while no tab exists. A new
+credential in KEYS after connecting is the prompt's attempt acting on the drawer's tick, which
+`ShellFlowTests.ThePrompt_NeverSavesAPassword_EvenWithTheDrawersTickLeftOn` exists to stop.
+
### 7.11 A host or a bucket made now can be picked on FILES now
With the files screen's picker open on an empty or short list, go to HOSTS and add a host — or to KEYS and
@@ -1421,7 +1454,7 @@ time)" — is the worse failure of the two: it rebinds a host as a side effect o
## Phase 8 — Adding and removing on the phone's host list
-Twenty-one checks, and the reason there are twenty-one rather than none is worth stating: **the layout suite
+Twenty-two checks, and the reason there are twenty-two rather than none is worth stating: **the layout suite
cannot see any of this and structurally never will.** `DodoSSH.Client.App.Layout.Tests` targets `net10.0` and
`DodoSSH.Client.Android` targets `net10.0-android`, so a project reference is impossible; Avalonia's
application, dispatcher and platform are one-shot process globals, so a second head cannot share the
@@ -1794,6 +1827,23 @@ follow, and try disconnecting and reconnecting instead.
---
+### 8.20 Connecting from the search box to a machine that is not saved
+
+With a terminal already open on some other machine, go back to HOSTS and type `user@host` for a reachable
+machine that is **not** in the list into the search box at the top. Type its password into the card that
+appears, and press CONNECT.
+
+**Pass:** the card appears only once there is an `@` in the box, names the address with `:22` on the end, and
+says NOT SAVED. CONNECT opens a second tab for `user@host` — the first is still there — and the fingerprint
+card asks about an unknown key over the terminal. Back on HOSTS the search box is empty, the list is the whole
+list again, and there is no new host in it. A port the parser refuses (`root@box:70000`) gives a sentence in
+amber under the box rather than a card.
+
+**Failure means:** the card sitting *over* the list rather than pushing it down is the panels' arrangement
+having been lost — see the remark above `IsSendingChosenHostsToAVault` in `HostsScreen.axaml`. A password that
+shows in the keyboard's suggestion strip is `Classes="secret"` missing from the box. Everything behind the
+card is `ShellFlowTests`' hosts-search cases; this is the rectangles, and the software keyboard.
+
## Phase 9 — Tag chips and the picker
The desktop half is measured by the layout suite, which now seeds three tags and puts all of them on one
@@ -2049,14 +2099,16 @@ that dialled it taken away. See `MainWindowViewModel.OnVaultConnectionFailed`.
With at least one keychain host and one machine connected to by hand in the log, open Connections with
nothing running.
-**Pass:** tapping the keychain one lands on HOSTS with that host **ticked and the action bar up**, ready
-for CONNECT out of the ⋯. Tapping the hand-typed one puts its address back in the box on this screen and
-leaves the password box **empty**. Neither one dials anything on its own.
+**Pass:** tapping the keychain one puts **its name** on the `connect to:` line and carries on as typing that
+name would — its password line, or straight into a terminal for a host with a key or a saved password.
+Tapping the hand-typed one puts its `user@host:port` on the line and asks for its password with the password
+line **empty**. Neither one leaves this screen, and the hand-typed one dials nothing until a password is
+given.
-**Failure means:** if the hand-typed one navigates to HOSTS, the log entry is carrying a host id it should
-not have. If the password came back, something is storing it — it never was. And if the keychain one arrives
-at a list with nothing marked, `ConnectToRecent` is setting the selection rather than going through
-`AskAboutHost`: nothing on that list means "selected" any more, so that is a screen with nothing to press.
+**Failure means:** if the hand-typed one shows a host's name rather than its address, the log entry is
+carrying a host id it should not have. If the password came back, something is storing it — it never was.
+And if the keychain one shows the logged address rather than the host's name, the host id is not being
+matched against the keychain — see `MainWindowViewModel.ChoosePromptRecentAsync`.
### 11.9 The keychain and snippets are the vault's, and back walks out of them
@@ -2285,6 +2337,23 @@ Android is not delivering the click as a `contextmenu` event, and the gesture ne
`WebView` instead of a page one. Neither costs this head anything it has today: a phone without a pointer
has no right button to miss.
+### 11.14 Connections with nothing open asks what to connect to
+
+Close every shell, then press **Connections**. Type part of a saved host's name into the `connect to:` line.
+
+**Pass:** the matching hosts appear under the line as buttons a thumb can hit; tapping one asks for that
+host's password on a line of its own under ssh's wording — or connects at once, for a host with a key or a
+saved password. Then type `user@host` for a machine that is not saved and press CONNECT: the password line
+appears with the keyboard already on it, and BACK — or the system back gesture — steps off it onto the
+address rather than leaving the screen. A tap on a RECENT row lands on the prompt and asks whatever it needs
+to before anything is dialled. Nothing new appears on HOSTS or in the keychain afterwards.
+
+**Failure means:** a password line that appears with the keyboard still on the first line is the posted focus
+in `ConnectPrompt.axaml.cs` arriving before the box has bounds. Back that leaves Connections from the password
+line is `PhoneShell.OnBackRequested`'s prompt step having been reordered below the surface check. The
+decisions themselves — which name matches, what is refused, what is saved — are `ShellFlowTests`' prompt
+cases, shared with the desktop; this is the rectangles and the keyboard.
+
---
## Phase 12 — Shared vaults: the operations that span two accounts
diff --git a/src/DodoSSH.Client.Android/Theme/Phone.axaml b/src/DodoSSH.Client.Android/Theme/Phone.axaml
index c6b42b7..37d7f8d 100644
--- a/src/DodoSSH.Client.Android/Theme/Phone.axaml
+++ b/src/DodoSSH.Client.Android/Theme/Phone.axaml
@@ -843,6 +843,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/DodoSSH.Client.Android/Views/ConnectPrompt.axaml.cs b/src/DodoSSH.Client.Android/Views/ConnectPrompt.axaml.cs
new file mode 100644
index 0000000..ce01e6e
--- /dev/null
+++ b/src/DodoSSH.Client.Android/Views/ConnectPrompt.axaml.cs
@@ -0,0 +1,45 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using Avalonia.Threading;
+
+namespace DodoSSH.Client.Android.Views;
+
+/// The phone's empty-terminal prompt: what to connect to, and its password when one is needed.
+///
+///
+/// The one thing the code-behind does is move the keyboard onto the password line when it appears. Enter on a
+/// name is answered with a second question, and a keyboard left on the first line — read-only by then — would
+/// type nothing and look as though it should.
+///
+///
+/// It does not take the keyboard when the screen opens, unlike the desktop's prompt. On a phone that would
+/// raise the software keyboard over the recent connections underneath, which are the likelier tap.
+///
+///
+/// FindControl rather than the generated x:Name fields, for the reason
+/// HostsScreen's constructor gives: no view on this head calls InitializeComponent, so those
+/// fields are null at run time.
+///
+///
+internal sealed partial class ConnectPrompt : UserControl
+{
+ public ConnectPrompt()
+ {
+ AvaloniaXamlLoader.Load(this);
+
+ var line = this.FindControl("PasswordLine")!;
+ var box = this.FindControl("Password")!;
+
+ line.PropertyChanged += (_, e) =>
+ {
+ if (e.Property == IsVisibleProperty && line.IsVisible)
+ {
+ // Posted at Loaded, as HostsScreen's own password sheet is: the box has no bounds on the turn
+ // its line becomes visible, and focusing a control with none raises no keyboard.
+ Dispatcher.UIThread.Post(() => box.Focus(NavigationMethod.Tab), DispatcherPriority.Loaded);
+ }
+ };
+ }
+}
diff --git a/src/DodoSSH.Client.Android/Views/HostsScreen.axaml b/src/DodoSSH.Client.Android/Views/HostsScreen.axaml
index 3280e6f..46652fe 100644
--- a/src/DodoSSH.Client.Android/Views/HostsScreen.axaml
+++ b/src/DodoSSH.Client.Android/Views/HostsScreen.axaml
@@ -72,7 +72,7 @@
-
@@ -82,6 +82,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -410,14 +375,13 @@