INC-2026-03-16: Resolution
Resolution
Decision: Clean reinstall of Termux from F-Droid.
Runbook: Z Fold 7 Mobile Workflow Setup
Reinstall Steps
-
Uninstall Termux (and plugins)
-
Install Termux from F-Droid (NOT Play Store)
-
pkg update && pkg upgrade -
pkg install openssh git neovim rsync stow pass gnupg fish oh-my-posh termux-api -
passwd/sshd/termux-setup-storage/whoami -
Phase 2: SSH key transfer and Vault cert auth
-
Phase 3-4: Git and GPG/gopass setup
-
Phase 5-6: Repos and dotfiles sync (dotfiles-optimus, domus-nvim)
-
Phase 7: Prompt setup (Starship - oh-my-posh broken on ARM64)
-
Phase 8: Clipboard for gopass (Termux:API app from F-Droid)
-
Phase 9: Set zsh as default shell
-
Phase 10: Clone productivity repos (domus-captures, domus-infra-ops)
-
Verify:
gopass ls,ssh -T git@github.com -
Remove temporary password auth from SSH config
Temporary SSH Config Change
File: ~/.ssh/config
Change: Enable password auth temporarily for initial connection (before keys transferred)
Apply Change
# Add PasswordAuthentication to fold7 entry
sed -i '/^Host fold7$/,/UserKnownHostsFile/{s/UserKnownHostsFile.*/&\n PasswordAuthentication yes\n PreferredAuthentications publickey,password/}' ~/.ssh/config
# Verify
grep -A 15 "^Host fold7$" ~/.ssh/config
Update User (after running whoami on phone)
# Replace old user with new (example: u0_a385 -> u0_a123)
sed -i '/^Host fold7$/,/^Host [^*]/{s/User u0_a385/User <NEW_USER>/}' ~/.ssh/config
Expected Result
Host fold7
HostName 10.50.10.110
Port 8022
- User u0_a385
+ User <whoami output>
IdentityFile ~/.ssh/id_ed25519_vault
CertificateFile ~/.ssh/id_ed25519_vault-cert.pub
IdentityFile ~/.ssh/id_ed25519_sk_rk_d000_nano
IdentityFile ~/.ssh/id_ed25519_sk_rk_d000
IdentityFile ~/.ssh/id_ed25519_sk_rk_d000_secondary
IdentityFile ~/.ssh/id_ed25519_d000
StrictHostKeyChecking no
UserKnownHostsFile ~/.ssh/known_hosts_mobile
+ PasswordAuthentication yes
+ PreferredAuthentications publickey,password
Revert After Keys Transferred
# Remove temporary password auth
sed -i '/^Host fold7$/,/^Host [^*]/{/PasswordAuthentication yes/d; /PreferredAuthentications publickey,password/d}' ~/.ssh/config
Remove PasswordAuthentication yes after keys are transferred.
|
Phase 2: SSH Key Transfer and Vault Cert
Generate Keypair on Phone
On phone (Termux):
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_vault -N "" -C "zfold7-termux"
Fetch Public Key to Workstation
Use sudo to bypass hardened SSH config (too many auth failures with 6 identity files).
|
# Copy public key from phone (use sudo due to SSH config)
sudo scp -o PubkeyAuthentication=no -P 8022 u0_a385@10.50.10.110:~/.ssh/id_ed25519_vault.pub /tmp/zfold7.pub
# Fix ownership (sudo created as root)
sudo chown evanusmodestus:evanusmodestus /tmp/zfold7.pub
Load Vault Credentials
dsource d000 dev/vault
vault status
Fix Vault Role: Add u0_a385 to allowed_users
Check current allowed_users (u0_a385 is NOT in list - only u0_a361 from old install):
vault read ssh/roles/domus-client -format=json | jq -r '.data.allowed_users | split(",") | .[]'
Get current allowed_users as comma-separated string for modification:
vault read ssh/roles/domus-client -format=json | jq -r '.data.allowed_users'
Update role to add u0_a385:
vault write ssh/roles/domus-client - <<'EOF'
{
"allowed_users": "Administrator,domus\\Administrator,admin,adminerosado,ansible,evanusmodestus,gabriel,root,u0_a361,u0_a385",
"key_type": "ca",
"default_user": "evanusmodestus",
"ttl": "8h",
"allow_user_certificates": true,
"default_extensions": {"permit-pty": "", "permit-user-rc": ""}
}
EOF
Verify u0_a385 is now in allowed_users:
vault read ssh/roles/domus-client -format=json | jq -r '.data.allowed_users | split(",") | .[] | select(test("u0_a"))'
Sign Certificate with Vault SSH CA
vault write -field=signed_key ssh/sign/domus-client \
public_key=@/tmp/zfold7.pub \
valid_principals="evanusmodestus,u0_a385" \
> /tmp/zfold7-cert.pub
Verify certificate:
ssh-keygen -L -f /tmp/zfold7-cert.pub | awk '/Principals:/{p=1} p && /^ /{print; if(/^[^ ]/)p=0}'
Copy Cert Back to Phone
sudo scp -o PubkeyAuthentication=no -P 8022 /tmp/zfold7-cert.pub u0_a385@10.50.10.110:~/.ssh/id_ed25519_vault-cert.pub
Copy Other SSH Keys to Phone
# Software keys (transferable)
sudo scp -o PubkeyAuthentication=no -P 8022 \
~/.ssh/id_ed25519_d000 \
~/.ssh/id_ed25519_d000.pub \
~/.ssh/id_ed25519_github \
~/.ssh/id_ed25519_github.pub \
~/.ssh/id_ed25519_gitlab \
~/.ssh/id_ed25519_gitlab.pub \
~/.ssh/id_ed25519_gitea \
~/.ssh/id_ed25519_gitea.pub \
~/.ssh/id_ed25519_codeberg \
~/.ssh/id_ed25519_codeberg.pub \
~/.ssh/id_ed25519_bitbucket \
~/.ssh/id_ed25519_bitbucket.pub \
~/.ssh/config \
u0_a385@10.50.10.110:~/.ssh/
# YubiKey keys (NOT transferable - hardware bound):
# - id_ed25519_sk_rk_d000_nano
# - id_ed25519_sk_rk_d000
# - id_ed25519_sk_rk_d000_secondary
Set Permissions on Phone
chmod 600 ~/.ssh/id_ed25519_*
chmod 644 ~/.ssh/*.pub ~/.ssh/*-cert.pub
chmod 600 ~/.ssh/config
Configure Phone authorized_keys for Cert Auth
Add workstation’s public key (fallback) and Vault CA (cert auth):
# From workstation - add d000 pubkey
cat ~/.ssh/id_ed25519_d000.pub | sudo ssh -o PubkeyAuthentication=no -p 8022 u0_a385@10.50.10.110 'cat >> ~/.ssh/authorized_keys'
# Add Vault CA for cert auth
vault read -field=public_key ssh/config/ca | awk '{print "cert-authority "$0}' | sudo ssh -o PubkeyAuthentication=no -p 8022 u0_a385@10.50.10.110 'cat >> ~/.ssh/authorized_keys'
Re-sign Workstation Cert with u0_a385 Principal
The workstation’s cert needs u0_a385 principal to authenticate to the phone:
vault write -field=signed_key ssh/sign/domus-client \
public_key=@$HOME/.ssh/id_ed25519_vault.pub \
valid_principals="Administrator,admin,adminerosado,ansible,domus\\Administrator,evanusmodestus,u0_a385" \
>| ~/.ssh/id_ed25519_vault-cert.pub
# Verify u0_a385 is in principals
ssh-keygen -L -f ~/.ssh/id_ed25519_vault-cert.pub | grep -A10 Principals
Verify SSH Works with Vault Cert
# From workstation (uses id_ed25519_vault with cert)
ssh fold7
Phase 3-4: Git and GPG/gopass Setup
Create SSH Sockets Directory (Phone)
mkdir -p ~/.ssh/sockets
Verify GitHub SSH (Phone)
ssh -T git@github.com
Transfer GPG Key from Workstation
On workstation:
# Export secret key
gpg --export-secret-keys --armor 28A3183647525597 > /tmp/gpg-secret.asc
# Copy to phone
sudo scp -P 8022 /tmp/gpg-secret.asc u0_a385@10.50.10.110:~/
# Clean up
rm /tmp/gpg-secret.asc
Import GPG Key (Phone)
# Import
gpg --import ~/gpg-secret.asc
# Trust the key
gpg --edit-key 28A3183647525597
# Type: trust → 5 → y → quit
# Verify
gpg --list-secret-keys
# Clean up
rm ~/gpg-secret.asc
Clone gopass Store (Phone)
mkdir -p ~/.local/share/gopass/stores
git clone git@github.com:EvanusModestus/gopass-v3.git ~/.local/share/gopass/stores/v3
Configure GPG Agent for Termux (Phone)
mkdir -p ~/.gnupg
echo "pinentry-program /data/data/com.termux/files/usr/bin/pinentry-tty" > ~/.gnupg/gpg-agent.conf
echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
# Restart gpg-agent
gpgconf --kill gpg-agent
gpg-agent --daemon
Configure gopass Mount (Phone)
Do NOT manually edit config file. Use gopass mounts add command.
|
# Add v3 store as mount
gopass mounts add v3 ~/.local/share/gopass/stores/v3
# Verify mount
gopass mounts
# Test
gopass ls
gopass show domains/d000/identity/ssh/github
Phase 5-6: Repos and Dotfiles Sync
Clone dotfiles-optimus (Phone)
mkdir -p ~/atelier/_projects/personal
git clone git@github.com:EvanusModestus/dotfiles-optimus.git ~/atelier/_projects/personal/dotfiles-optimus
Clone domus-nvim (Phone)
git clone git@github.com:EvanusModestus/domus-nvim.git ~/.config/nvim
Build blink.cmp Fuzzy Matcher (Phone)
blink.cmp requires Rust build for performance:
pkg install rust binutils make clang
cd ~/.local/share/nvim/lazy/blink.cmp
cargo build --release
Install LSPs via Termux (Phone)
Mason doesn’t work on Termux (no Android binaries). Install LSPs directly:
# Node.js for npm-based LSPs
pkg install nodejs-lts
# TypeScript/JavaScript
npm install -g typescript typescript-language-server
# Python
npm install -g pyright
# Bash
npm install -g bash-language-server
# YAML/JSON/HTML/CSS
npm install -g yaml-language-server vscode-langservers-extracted
# Rust
pkg install rust-analyzer
# C/C++
pkg install clang
Configure Neovim for Termux (domus-nvim)
File: ~/.config/nvim/lua/domus/plugins/config/lsp/init.lua
Add at top of file:
---@diagnostic disable: undefined-global
Wrap ensure_installed to skip on Termux (around line 48):
require("mason-lspconfig").setup({
ensure_installed = vim.fn.isdirectory("/data/data/com.termux") == 1 and {} or {
"lua_ls", "pyright", "rust_analyzer", "ts_ls",
-- ... rest of servers
},
Add Termux fallback after mason-lspconfig.setup() closes (before function end):
-- Termux fallback: setup LSPs using nvim 0.11 native API
if vim.fn.isdirectory("/data/data/com.termux") == 1 then
vim.lsp.config.lua_ls = {
cmd = { "lua-language-server" },
filetypes = { "lua" },
root_markers = { ".git", ".luarc.json", "init.lua" },
settings = { Lua = { diagnostics = { globals = { "vim" } } } },
}
vim.lsp.config.pyright = {
cmd = { "pyright-langserver", "--stdio" },
filetypes = { "python" },
root_markers = { ".git", "pyproject.toml", "setup.py" },
}
vim.lsp.config.rust_analyzer = {
cmd = { "rust-analyzer" },
filetypes = { "rust" },
root_markers = { ".git", "Cargo.toml" },
}
vim.lsp.enable({ "lua_ls", "pyright", "rust_analyzer" })
end
File: ~/.config/nvim/lua/domus/plugins/specs/lang/markdown.lua
Disable obsidian.nvim on Termux:
{
"epwalsh/obsidian.nvim",
cond = vim.fn.isdirectory("/data/data/com.termux") == 0, -- disable on Termux
-- ...
},
Mason errors on startup are expected until ensure_installed is wrapped. System-installed LSPs work via native fallback.
|
Stow Shell and Tool Configs (Phone)
Available in base/: fish, zsh, git, vim, fzf, fd, ripgrep, gpg
cd ~/atelier/_projects/personal/dotfiles-optimus/base
# Fish shell
stow -t ~ fish
# Zsh shell
stow -t ~ zsh
# Git config
stow -t ~ git
# Vim (fallback)
stow -t ~ vim
# Search tools
stow -t ~ fzf
stow -t ~ fd
stow -t ~ ripgrep
Phase 7: Prompt Setup (Phone)
Oh-My-Posh - BROKEN on ARM64 Termux
Oh-my-posh crashes on ARM64 Termux with Go runtime panics (writeSegmentsConcurrently race condition). All themes crash, including built-in minimal themes. disable_async = true does not fix it.
|
Do NOT use oh-my-posh on Termux.
Solution: Use Starship Instead
Starship is Rust-based and works reliably on ARM64.
# Install starship
curl -sS https://starship.rs/install.sh | sh -s -- --bin-dir ~/.local/bin
# Remove oh-my-posh if installed
rm -f ~/.local/bin/oh-my-posh
rm -rf ~/.cache/oh-my-posh
Configure Starship in .zshrc
Comment out oh-my-posh block and add starship:
# Comment out oh-my-posh (broken on ARM64)
sed -i '/^if command -v oh-my-posh/,/^fi$/s/^/#/' ~/.zshrc
# Add starship init
echo 'eval "$(starship init zsh)"' >> ~/.zshrc
Apply a Powerline Theme
# List available presets
starship preset --list
# Apply tokyo-night (matches workstation theme)
starship preset tokyo-night -o ~/.config/starship.toml
# Or catppuccin-powerline
starship preset catppuccin-powerline -o ~/.config/starship.toml
exec zsh
Expected Result
Powerline-style prompt with git status, path, and exit code:
u0_a385 …/dotfiles-optimus/apps main ! 20:11 ❯
Phase 8: Clipboard for gopass (Phone)
gopass requires clipboard access for gopass show -c to work.
Install Termux:API App
| You need BOTH the package AND the Android app. |
-
Package (CLI tools):
pkg install termux-api -
Android App (handles API calls):
Install from F-Droid: f-droid.org/packages/com.termux.api/
| Without the Android app, clipboard commands hang forever. |
Test Clipboard
echo "test" | termux-clipboard-set
termux-clipboard-get
Use with gopass
# Copy password to clipboard (clears after 45s)
gopass show -c domains/d000/identity/ssh/github
# Manual workaround if -c doesn't work
gopass show domains/d000/identity/ssh/github | head -1 | termux-clipboard-set
Phase 9: Set zsh as Default Shell
Bash is the default Termux shell. Change to zsh for consistency with workstation.
Change Default Shell (Phone)
# Set zsh as default
chsh -s zsh
# Verify
cat /data/data/com.termux/files/usr/etc/passwd | grep $(whoami)
Expected output:
u0_a385::10385:10385::/data/data/com.termux/files/home:/data/data/com.termux/files/usr/bin/zsh
Force zsh on Termux Start
If chsh doesn’t persist (some Termux versions), add to .bashrc:
echo 'exec zsh' >> ~/.bashrc
Verify (Close and Reopen Termux)
Terminal should show zsh prompt (starship) instead of bash $:
u0_a385 ~ 20:30 ❯
Phase 10: Mobile Productivity Repos
Clone repos to enable productive mobile workflow. Z Fold 7’s large screen makes AsciiDoc editing and studying practical.
Create Atelier Structure (Phone)
mkdir -p ~/atelier/_bibliotheca
mkdir -p ~/atelier/_projects/personal
Clone domus-captures (Phone)
Primary use: Regex training, worklogs, codex references.
git clone git@github.com:EvanusModestus/domus-captures.git ~/atelier/_bibliotheca/domus-captures
Clone domus-infra-ops (Phone)
Primary use: Runbook reference while on-call.
git clone git@github.com:EvanusModestus/domus-infra-ops.git ~/atelier/_bibliotheca/domus-infra-ops
Clone domus-netapi-docs (Phone)
Primary use: netapi CLI reference.
git clone git@github.com:EvanusModestus/domus-netapi-docs.git ~/atelier/_bibliotheca/domus-netapi-docs
Convenience Aliases
Add to ~/.zshrc or create in dotfiles:
# Quick nav aliases
alias dcap='cd ~/atelier/_bibliotheca/domus-captures'
alias dinfra='cd ~/atelier/_bibliotheca/domus-infra-ops'
alias dnetapi='cd ~/atelier/_bibliotheca/domus-netapi-docs'
# Today's worklog
alias wrklog='nvim ~/atelier/_bibliotheca/domus-captures/docs/modules/ROOT/pages/$(date +%Y/%m)/WRKLOG-$(date +%Y-%m-%d).adoc'
# Regex training
alias regex='cd ~/atelier/_bibliotheca/domus-captures/docs/modules/ROOT/pages/education/training/regex && nvim .'