Hi @Luke Boswell — I'd like to take basic-cli #223. Wanted to sanity-check the approach first, since you flagged it as more than a beginner task.
I think it can be pure Roc, no new host function: read PATH via Env.var! (byte-preserving through OsStr), branch on Env.platform!, and check candidates with Path.is_executable! — which already handles the Unix exec-bit and follows symlinks. (On Windows I'd read %PATHEXT% to build the candidate extensions.)
The one call I'd flag: is_executable! also returns true for a directory (dirs carry 0o111), so a directory named like the command would false-positive. The Rust reference in the issue has the same edge — I'd match it and document it. Excluding it exactly would mean a new host primitive, i.e. the ABI surface the triage was wary of, so I'm leaning against that unless you'd rather have exact which semantics.
Leaning Cmd.check_available! : Str => Bool to match the issue; could return the resolved Path instead if that's more useful.
It would be nice if we could avoid the failure mode with directories, but I think its also fine to implement in pure roc with a note or maybe a TODO to revisit in future. I dont feel strongly about it or anything.
Thanks! Turned out I could avoid the directory case in pure Roc after all: a candidate must be executable (or exist, on Windows) and not be a directory. Since is_dir! doesn't follow symlinks, a symlink to an executable still resolves while a real directory named like the command is rejected — verified with a dir, a symlink, and a real executable all sharing a name. The only residual is a symlink pointing at a directory, which I've noted.
Opened as #466.
Last updated: Aug 12 2026 at 12:35 UTC