Skip to content

enhancement: apm install --root <dir> to target a directory other than $PWD #888

Description

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:

  1. 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.
  2. 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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/cliCLI command surface, flags, help text (cross-cutting).area/docs-sitedocs/src/content (Starlight), README, doc generation.priority/lowHuman-set low priority; does not imply acceptance, implementation approval or a release target.status/acceptedHuman scope approval; verify the issue's approval record and review contact before work.status/triagedAutomated advice completed; deduplication only. Not human approval; silence is not approval.theme/portabilityOne manifest, every target. Multi-target deploy, marketplace, packaging, install.type/featureNew capability, new flag, new primitive.

    Type

    No type

    Projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions