cd /news/ai-agents/shellcheck-passed-every-file-the-pip… · home › topics › ai-agents › article
[ARTICLE · art-154363] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

ShellCheck Passed Every File. The Pipeline Was Still Broken.

A developer built script-chain-walk, a zero-dependency Python CLI (stdlib only, Python 3.9+) that traces cross-file script call chains to catch failures single-file linters miss. Pointed at a directory, it builds a dependency graph and flags broken chains (calls to files that don't exist) and call cycles, using a bash extractor and Python's ast module to detect subprocess, os.system, exec and runpy invocations. It offers JSON output, single-chain tracing via --entry, and a --check mode that exits 1 on broken or cyclic chains for CI pipelines and agent guardrails.

by read2 min views3 publishedOct 21, 2026

ShellCheck is great at what it does. So is Pylint. So is every linter you've

ever run in CI. They all share one blind spot: they look at one file at a time.

Here's the failure mode that keeps biting me. A deploy script calls

./cleanup.sh. The linter passes. The pipeline runs. And it fails — because

cleanup.sh was renamed two sprints ago and nobody updated the caller. No

linter on earth flags a call to a file that doesn't exist, because no linter

is looking at the relationships between files.

The same blind spot shows up with agents. An AI agent writes a tidy little

setup.sh, then a run.py that calls it via subprocess, then a wrapper

that calls run.py… and somewhere in the middle there's a loop, or a dead

reference, and you only find out at 2 AM. What you want in that moment isn't

a per-file report. It's a map: which script calls which, where the chain

dead-ends, and where it loops back on itself.

I built that map.

script-chain-walk — a zero-dependency Python CLI (stdlib only, Python ≥

3.9) that traces cross-file script call chains. Point it at a directory and

it builds the full dependency graph, then flags two things linters can't

see: broken chains (calls to files that don't exist) and call cycles.

pip install script-chain-walk
walk ./scripts

Example output on a messy deploy directory:

deploy.sh
|-- migrate.py  (line 3, exec)
|   `-- seed.sh  (line 12, exec)
`-- notify.sh  (line 5, exec)

scripts: 4   edges: 3   broken: 1   cycles: 0

BROKEN CHAINS (call target not found):
  notify.sh:8 -> ./cleanup.sh (exec, missing)

There's also --format json for machine-readable output, --entry to trace one chain, and

deploy.sh--check, which exits 1 if anything is

broken or cyclic — made for CI pipelines and agent guardrails.

Two extractors, no regex soup on the Python side:

bash foo.sh, ./foo.sh, sh -x foo.sh, source lib.sh, . lib.sh, python3 bar.py, exec ./foo.sh. ast module. Detects subprocess.run(...), os.system(...) / os.popen(...), os.execv(...) and friends, exec(open("other.py").read()), and runpy.run_path("other.py"). Every target is resolved against the directory tree — relative to the

caller first, then by unique basename match elsewhere in the tree, with

absolute paths honored. Anything unresolvable is reported as broken (or

ambiguous, when several files share the name). Cycles come from a DFS over

the graph; entry points are scripts nothing calls.

Because that's a different job. ShellCheck and Pylint answer "is this file

correct?" script-chain-walk answers "does this system of scripts hold

together?" A single-file tool will never tell you that a.sh calls b.py

calls c.sh calls a.sh. If you run coding agents that generate scripts,

walk --check on their output directory is a thirty-second audit of what

the agent actually wired up — dead scripts it keeps "calling" and accidental

recursion included.

pip install script-chain-walk — stdlib only, no dependencies, MIT licensed.

If it finds a broken chain in your repo, I'd genuinely like to hear about it.

── more in #ai-agents 4 stories · sorted by recency
── more on @script-chain-walk 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/shellcheck-passed-ev…] indexed:0 read:2min 2026-10-21 · —