`cli.Main` ran the command tree on a background context, so SIGINT, SIGTERM or SIGHUP killed the process before deferred cleanup ran: `ssh to` left its agent socket and directory behind, and `ssh install` left a copy of the host's `authorized_keys` in its working directory. `Main` now runs the tree on a `signal.NotifyContext` for those signals; the cancelled context ends the child `ssh` or `sftp` and the cleanup runs. `ssh to` stops its child with SIGTERM, not a kill, so `ssh` restores the terminal. Exit status after a signal is 1 unless `ssh` reported its own.
The test re-runs the test binary as the tool, waits for the agent socket, sends each signal and checks the directory is gone.
Disclosure: the repeated `"uptime"` test literal became a `remoteCommand` constant because `goconst` required it.
Model: opus-4-8 (implementation, review); fable-5-1 (merge message)
`keyfunc ssh to` and `keyfunc ssh install` started the system `ssh` and `sftp` with the tool's whole environment, so a mnemonic given in `KEYFUNC_MNEMONIC` stayed readable in the child's environment and could be forwarded to the host by a `SendEnv` line. Both children now get the environment with `KEYFUNC_MNEMONIC` and `KEYFUNC_MNEMONIC_COMMAND` removed, through one helper, `childEnv`, in the ssh cli package. The mnemonic command still runs with the full environment. Two tests drive the real commands against the stand-in `ssh` and `sftp` and check that a third variable still arrives.
Model: opus-4-8 (implementation, review); fable-5-1 (merge message)
The first sftp session now lists .ssh before fetching authorized_keys. The file reads as empty only when sftp reports .ssh itself as missing, or the listing succeeded and the file is reported missing. A directory or file that is there but cannot be read fails the run and nothing is written, so no existing authorized_keys is replaced by content that was not built from what was read. An .ssh that already exists keeps its mode; the directory is made and set to 0700 only when none was found. The README describes the rule and states batch mode's limit: a key or an agent must authenticate.
Model: opus-4-8 (implementation); fable-5-1 (summary)
keyfunc --version printed dev for any binary not built with make build. When no version was stamped at build time, the tool now reports the module version recorded in the binary's build info, which go install fills in. A stamped version still wins, and a local build with neither still prints dev.
Model: opus-4-8 (implementation); fable-5-1 (summary)
ssh install no longer runs a command on the host. It reads .ssh/authorized_keys over sftp, takes the empty reading only from sftp's own message about that path, appends the derived key locally when it is not already present, uploads the result beside the file with mode 0600 and renames it over the original. Any other failure prints what sftp said, writes nothing and exits 1. sftp batch mode disables password prompts, so a key or agent is required; a directory the owner cannot enter reads as a host with no file, which README.md states.
Model: opus-5 (implementation); fable-5-1 (landing)
keyfunc ssh install appends the public line on a host through the system ssh, only when absent, feeding the line on standard input; keyfunc ssh to serves the derived key from an in-process agent on a private socket and runs the system ssh with it, the private key never on disk. Two review rounds; the second passed with no findings.
Model: opus-5 (implementation and review); fable-5-1 (landing)
keyfunc age derives an age identity at the generic path the way secret's agehd does, prints the recipient or the identity, and encrypts to or decrypts with it, the derived recipient always among encrypt's recipients. Two review rounds; the second passed with no findings, the clamping step now pinned by a fixed identity test.
Model: opus-5 (implementation and review); fable-5-1 (landing)
keyfunc mnemonic derives a 12, 18 or 24 word child mnemonic through BIP-85's own mnemonic application, with the specification's test vectors as tests. One review round, passed with no findings; the reviewer reproduced the vectors from an implementation written from the specification alone.
Model: opus-5 (implementation and review); fable-5-1 (landing)
The module, the script entrypoints and Makefile, Docker-only linting, the mnemonic sources in the specified order with their refusals, the BIP-85 derivation, and keyfunc ssh pub and priv with the README test vectors as tests. Two review rounds; the second passed with no findings.
Model: opus-5 (implementation and review); fable-5-1 (landing)