Developer CLI Tooling Precedence and Dot-Directory Resolution¶
Status: Accepted (Amends ADR 0005 and ADR 0043)
We establish an explicit precedence hierarchy for developer CLI tooling (agyq, ghls, ghpr, ghclone, agyprofile, decrypt-repo-env, encrypt-repo-env) inside Modal sandboxes and implement dynamic dot-directory resolution across shared/image.py to prevent stale container binaries from shadowing active repository versions and staged scripts.
Context¶
ADR 0043 migrated staging directories from /root/scripts and /root/secrets to hidden dot-directories /root/.scripts and /root/.secrets. However, two integration gaps emerged:
- Static Local Path Resolution in
shared/image.py:LOCAL_SCRIPTS_DIRwas hardcoded toREPO_ROOT / "scripts". Inside the hosted Modal control plane container (sandbox/function.py) and inside active sandboxes, scripts are staged into/root/.scriptsand secrets into/root/.secrets. As a result,LOCAL_SCRIPTS_DIRresolved to non-existent/root/scripts, causingadd_local_files_if_present()to silently skip developer CLI tools when building sandbox images from within the control plane. - Stale Pre-baked Image Binary Precedence in
shared/startup.sh: Inshared/startup.sh, the staging loop guarded symlink creation with[ ! -f "/usr/local/bin/$cmd" ]. Because the pre-baked Modal base image already contains older versions of developer CLI utilities in/usr/local/bin, the guard prevented newly staged scripts in/root/.scriptsfrom overwriting stale base image binaries. - Absence of Workspace Repository Precedence:
When launching a development sandbox for a repository that provides updated versions of developer utilities (such as
software-factorywith updated rolling quota logic inscripts/agyq),startup.shdid not inspect$TARGET_DIR/scripts. Consequently, commands executed on$PATHinvoked the stale pre-baked/usr/local/binbinary rather than the live repository version checked out in the workspace.
Decisions¶
- Developer CLI Tooling Precedence Hierarchy:
We establish a strict three-tier precedence order for developer CLI binaries on
$PATH: - Tier 1: Workspace Repository (
$TARGET_DIR/scripts): If the cloned or resumed target repository provides developer CLI tools (or Python counterparts such asdecrypt_repo_env.py),shared/startup.shsymlinks them into/usr/local/bin, giving live workspace scripts highest priority. - Tier 2: Staged Dot Directory (
/root/.scripts): For sandboxes without workspace repository scripts (or standalone sandboxes), staged scripts in/root/.scripts(or/root/scripts) force-symlink (ln -sf) into/usr/local/bin, overwriting stale image fallbacks. -
Tier 3: Pre-baked Base Image Binary (
/usr/local/bin): The base container binaries serve as the ultimate fallback when neither workspace repository scripts nor staged dot-directory scripts exist. -
Dynamic Dot-Directory Script and Secret Resolution in
shared/image.py: - Introduce dynamic resolution helpers (
_resolve_dirand_resolve_file) inshared/image.pyinspecting candidate directories (scripts,.scripts,/root/.scripts,/root/scripts,.secrets,secrets,/root/.secrets,/root/secrets). - Define both
LOCAL_SCRIPTS_DIRandLOCAL_SECRETS_DIRdynamically to track valid directory roots across host developer machines, control plane containers, and active sandboxes. -
Ensure all developer CLI tools (
LOCAL_AGYQ,LOCAL_GHLS, etc.) and secrets (LOCAL_OPENCODE_SECRET,LOCAL_ANTIGRAVITY_SECRET*,LOCAL_MODAL_SECRET,LOCAL_CLOUDFLARE_SECRET,LOCAL_GITHUB_ORGS_SECRET) resolve existing disk files across both dot-prefixed and non-dot-prefixed staging paths. -
Convenience Symlink Cycle Prevention: In
shared/startup.sh, convenience symlinks in/root/.scriptspointing to/usr/local/binverify realpaths to prevent circular symlink chains between/root/.scripts/$cmdand/usr/local/bin/$cmd.
Consequences¶
- Live Script Reactivity: Updates to scripts in
$TARGET_DIR/scripts(such asscripts/agyqrolling quota calculations) immediately take effect in/usr/local/binand$PATHwithout requiring image rebuilds or manual symlink recreation. - Control Plane Consistency: When the hosted control plane (
sandbox/function.py) builds sandbox images,shared/image.pyaccurately discovers staged developer tools in/root/.scriptsand secrets in/root/.secrets. - Clean Fallback Chain: Environments without a target repository or staged files gracefully fall back to base image binaries.