DEV Community

Jordan Huang
Jordan Huang

Posted on

FAQ: Five Myths About Agent-Installed Dependencies

Did the agent actually install that package?
The chat says yes. The next import says no.

I keep seeing this exact gap.
The log looks green. The environment is not.

This FAQ is not a model-IQ rant.
It is a state problem. Files versus sentences.

Why this keeps biting people

Agent loops narrate work in English.
Package managers speak exit codes and hashes.

We mix those two languages constantly.
Then we trust the wrong one. Why?

I want isolation from my laptop.
A free remote server is useful for that.

A free model can drive the install commands.
I still read the files myself. Always.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

MonkeyCode is optional for this checklist.
The same checks run on any host you control.

Start with evidence, not vibes

Do not argue with the transcript.
Print four facts. Save both outputs.

  • Which interpreter actually ran.
  • Which lockfile hashes currently exist.
  • Whether pip knows the distribution.
  • Whether Python can import the module.

Here is a proposed script.
Treat it as a template, not a scoreboard.

#!/usr/bin/env bash
# verify-install.sh — proposed checklist, not a benchmark
set -u
IMPORT_NAME="${1:-}"
DIST_NAME="${2:-$IMPORT_NAME}"

echo "=== identity ==="
echo "utc=$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo "host=$(hostname)"
echo "pwd=$(pwd)"
echo "path_python=$(command -v python3 || echo missing)"

python3 - <<'PY'
import sys, platform
print("py_version=" + sys.version.split()[0])
print("py_exec=" + sys.executable)
print("py_prefix=" + sys.prefix)
print("platform=" + platform.platform())
PY

echo "=== declared files ==="
for f in requirements.txt pyproject.toml poetry.lock Pipfile.lock \
         package.json package-lock.json pnpm-lock.yaml yarn.lock; do
  if [ -f "$f" ]; then
    echo "present=$f sha256=$(sha256sum "$f" | awk '{print $1}')"
  else
    echo "missing=$f"
  fi
done

if [ -n "$DIST_NAME" ]; then
  echo "=== pip show $DIST_NAME ==="
  python3 -m pip show "$DIST_NAME" || echo "pip_show_fail=$DIST_NAME"
fi

if [ -n "$IMPORT_NAME" ]; then
  echo "=== import $IMPORT_NAME ==="
  python3 - "$IMPORT_NAME" <<'PY'
import importlib.util
import sys
name = sys.argv[1]
spec = importlib.util.find_spec(name)
print("import_name=" + name)
print("found=" + str(spec is not None))
if spec is not None and spec.origin:
    print("origin=" + spec.origin)
sys.exit(0 if spec is not None else 1)
PY
  echo "import_exit=$?"
fi
Enter fullscreen mode Exit fullscreen mode

Run it before the agent installs anything.
Run it after. Diff the two dumps.

No hash change, plus a failed import?
The chat lied, or it used another machine.

On macOS, swap sha256sum for shasum -a 256.
GNU coreutils is an assumption. Print your tool.

Myth 1: The chat log means installed

The agent typed pip install pydantic.
Then it said done. Did you believe it?

Ask a better question instead.
What did pip show print on that host?

Claim people repeat: the sentence is the result.
Evidence to collect: pip metadata and an import.
Corrected model: narration is not environment state.

Commands I actually want:

python3 -m pip show pydantic
python3 -c "import pydantic; print(pydantic.__file__)"
echo "import_exit=$?"
Enter fullscreen mode Exit fullscreen mode

If pip show fails, the install did not happen.
If import fails, you likely used the wrong name.

Green prose in a transcript is cheap.
An import path on disk is not cheap.

Myth 2: Import name equals PyPI name

This one burns people every week.
The agent installs pillow. You import pillow.

It fails. You blame the remote server.
You should blame the name mapping.

Claim people repeat: the string is one object.
Evidence to collect: dist metadata versus find_spec.
Corrected model: distributions and import packages differ.

Keep this table near the script:

You install You import Trap
pillow PIL different names
beautifulsoup4 bs4 different names
scikit-learn sklearn different names
PyYAML yaml case plus alias
opencv-python cv2 different names
python-dateutil dateutil prefix dropped

Probe both names. Do not guess.
Do not interpolate raw agent text into bash.

python3 -m pip show pillow || echo "missing_dist=pillow"
python3 - <<'PY'
import importlib.util
spec = importlib.util.find_spec("PIL")
print("found", spec is not None)
print("origin", getattr(spec, "origin", None))
PY
Enter fullscreen mode Exit fullscreen mode

Why hardcode the names here?
Because agent output is untrusted shell input.

Myth 3: A successful install kept the lock honest

pip install foo can succeed without a lockfile.
It can also ignore the lock you already have.

Did poetry.lock actually change?
Did package-lock.json actually change?

If the hash is identical, the lock was unused.
The agent likely installed into a floating env.

Claim people repeat: green install means reproducible.
Evidence to collect: before and after hashes.
Corrected model: success is not a resolver proof.

cp poetry.lock /tmp/lock.before
# agent runs install here
sha256sum poetry.lock /tmp/lock.before
diff -u /tmp/lock.before poetry.lock || true
Enter fullscreen mode Exit fullscreen mode

For npm, ask git. It already knows.

git status --short package-lock.json pnpm-lock.yaml yarn.lock
git diff -- package-lock.json
Enter fullscreen mode Exit fullscreen mode

No diff, but node_modules grew anyway?
You installed off-lock. CI may not follow.

Floating versions feel fast in a chat.
They become a different tree on the next host.

Myth 4: python3 is the project interpreter

The agent ran python3 -m pip install -r requirements.txt.
Which python3 did that PATH resolve to?

System? pyenv? .venv? A leftover conda prefix?
The first hit is not a contract.

Claim people repeat: the command name is enough.
Evidence to collect: sys.executable and sys.prefix.
Corrected model: PATH is session state, not project state.

command -v python3
readlink -f "$(command -v python3)" || true
python3 -c "import sys; print(sys.executable); print(sys.prefix)"
ls -l .venv/bin/python || echo "no_venv"
Enter fullscreen mode Exit fullscreen mode

If sys.prefix is not your venv, stop.
Call the venv binary. Do not hope.

test -x .venv/bin/python
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python -c "import sys; print(sys.prefix)"
Enter fullscreen mode Exit fullscreen mode

Remote free servers often expose a system Python.
Your laptop might already be inside .venv.

I am not claiming any vendor default version.
I am saying you must print it every session.

Same rule for Node, by the way.
which node and node -v are different stories.

command -v node
node -v
test -x node_modules/.bin/node && echo "local_bin_exists"
Enter fullscreen mode Exit fullscreen mode

Myth 5: Uninstall means the module is gone

The agent says it uninstalled numpy.
The next turn still imports numpy. How?

Cache? Another interpreter? Stale .pyc files?
Or a second copy in user site-packages.

Claim people repeat: uninstall is global and complete.
Evidence to collect: __file__ before and after.
Corrected model: uninstall is per interpreter location.

Print the path first. Then remove it.

python3 -c "import numpy; print(numpy.__file__)"
python3 -m pip uninstall -y numpy || true
python3 -m pip cache purge || true
python3 -c "import numpy" ; echo "import_exit=$?"
python3 -m site
Enter fullscreen mode Exit fullscreen mode

Still importing after a zero exit code?
You killed one copy. Another copy remains.

User site plus venv is a common split.
The agent only targeted one of them.

Decision table I keep beside the script

Observation Do not conclude Conclude instead
Chat said installed The module is importable Run pip show and import
pip show works CI will match this host Record Python and platform
Lockfile hash unchanged The env is clean Install may be off-lock
Import works in this shell The next turn will work Confirm the same sys.executable
Uninstall returned 0 The module is gone Import again on that binary

Paste this table into a PR comment.
It beats another "please try again" ping.

A workflow I actually follow

  1. Snapshot with verify-install.sh.
  2. Let the agent run the install command.
  3. Snapshot again and diff the files.
  4. Import on the same executable only.
  5. Then allow the next refactor step.

Need isolation from your laptop packages?
Run both snapshots on a free remote server.

Keep secrets off that box.
This checklist does not need API tokens.

If the server is ephemeral, expect amnesia.
Rerun the snapshot at session start. Every time.

Limitations

This does not prove the library works.
Importable is not the same as tests passed.

Wheels can import and still crash on call.
Optional extras can stay missing until runtime.

The script ignores CPU flags on native wheels.
It also ignores mirrors and yanked versions.

sha256sum is not universal on macOS.
pip cache purge may no-op on old pip.

I am not giving quotas, model names, or hardware.
Those change. Files and exit codes do not.

Who should not use this approach

Do not use a shared free server for private packages.
Internal indexes and tokens do not belong there.

Do not skip CI because an agent imported a module.
This FAQ is a debug lens, not a release gate.

Do not interpolate agent-supplied names into your shell.
That is how a surprise rm gets executed.

If you cannot list files on the host, stop.
A chat UI is not a package manager.

Hermetic build pipelines should ignore this FAQ.
You already have lockfiles and pinned images. Use them.

What I want you to remember

Ask where it installed. Ask which interpreter.
Ask whether the lockfile actually moved.

Then ask if you can import it now.
Four answers. Not one paragraph of confidence.

Got a lockfile hash that refused to move?
Drop both snapshots in the comments. I will read them.

Top comments (0)