Problem
apm install always writes relative to $PWD. There's no flag to redirect deployment to a different root.
This forces scratch-dir verification workflows (see #684) to physically stage every input file in the scratch tree and cd into it, rather than running apm install --root <scratch> against inputs that stay in place.
Concrete workaround in the wild
juspay/kolu runs apm install in a scratch directory as part of just ci — the motivating use case on #684. The workaround currently spans ~20 lines of a justfile recipe (agents/ai.just:49-77):
scratch=$(mktemp -d)
trap 'rm -rf "$scratch"' EXIT
rsync -a \
--exclude='.git/' \
--exclude='node_modules/' \
--exclude='.direnv/' \
--exclude='.logs/' \
--exclude='.claude/' \
--exclude='.codex/' \
--exclude='.agents/' \
--exclude='.opencode/' \
--exclude='CLAUDE.md' \
"$PWD/" "$scratch/"
mkdir -p "$scratch/.claude" "$scratch/.codex" "$scratch/.opencode" "$scratch/.agents"
[[ ! -e .claude/launch.json ]] || cp .claude/launch.json "$scratch/.claude/launch.json"
[[ ! -e .codex/config.toml ]] || cp .codex/config.toml "$scratch/.codex/config.toml"
(cd "$scratch" && apm install >/dev/null)
(cd "$scratch" && apm compile --target codex,opencode >/dev/null)
Every line between scratch=$(mktemp -d) and (cd "$scratch" && apm install ...) exists only because apm install can't take a target directory. With a --root flag this collapses to roughly:
scratch=$(mktemp -d)
trap 'rm -rf "$scratch"' EXIT
apm install --root "$scratch"
apm compile --root "$scratch" --target codex,opencode
Why --root (not cd-based workaround) is the right primitive
- No input duplication. The current workaround copies the entire worktree into scratch (7 exclude rules, a pair of
cp fallbacks for user-owned runtime files, and mkdirs to satisfy target auto-detection). A --root flag keeps sources in place — apm.yml, the lockfile, and local-path packages all resolve from $PWD while writes land under --root.
- Uses beyond verification. Scripted setup scenarios (bootstrap scripts, fixture generation for tests, CI dry-runs) all benefit from installing into a specific directory without chdir gymnastics.
- Matches precedent.
pip install --target, npm install --prefix, cargo install --root — redirecting output root is a standard package-manager affordance.
Scope
Two sub-questions the implementation will need to resolve:
- Which paths does
--root redirect? I'd expect: deployed-file writes (.claude/, .codex/, .agents/, .opencode/), apm_modules/, and the lockfile. Sources (apm.yml, local-path package roots) should continue resolving from $PWD unless a separate --manifest flag is added.
- Interaction with
apm compile. compile has the same scratch-dir use case (see the (cd "$scratch" && apm compile ...) line above). Worth applying the same flag to compile and any other command that writes to the working directory.
References
Environment
- apm 0.9.2 (via
uvx --from git+https://github.com/juspay/apm apm — pinned to juspay fork for an unrelated fix)
Problem
apm installalways writes relative to$PWD. There's no flag to redirect deployment to a different root.This forces scratch-dir verification workflows (see #684) to physically stage every input file in the scratch tree and
cdinto it, rather than runningapm install --root <scratch>against inputs that stay in place.Concrete workaround in the wild
juspay/kolu runs
apm installin a scratch directory as part ofjust ci— the motivating use case on #684. The workaround currently spans ~20 lines of a justfile recipe (agents/ai.just:49-77):Every line between
scratch=$(mktemp -d)and(cd "$scratch" && apm install ...)exists only becauseapm installcan't take a target directory. With a--rootflag this collapses to roughly:Why
--root(notcd-based workaround) is the right primitivecpfallbacks for user-owned runtime files, andmkdirs to satisfy target auto-detection). A--rootflag keeps sources in place —apm.yml, the lockfile, and local-path packages all resolve from$PWDwhile writes land under--root.pip install --target,npm install --prefix,cargo install --root— redirecting output root is a standard package-manager affordance.Scope
Two sub-questions the implementation will need to resolve:
--rootredirect? I'd expect: deployed-file writes (.claude/,.codex/,.agents/,.opencode/),apm_modules/, and the lockfile. Sources (apm.yml, local-path package roots) should continue resolving from$PWDunless a separate--manifestflag is added.apm compile.compilehas the same scratch-dir use case (see the(cd "$scratch" && apm compile ...)line above). Worth applying the same flag tocompileand any other command that writes to the working directory.References
audit --ci— Sergio + Daniel both mentioned--rootin their triage replies)agents/ai.just:49-77Path.cwd()/get_deploy_root(scope):src/apm_cli/commands/install.py:1191,1271,1283,1424Environment
uvx --from git+https://github.com/juspay/apm apm— pinned to juspay fork for an unrelated fix)