Problem
shiv-generated shims currently export:
That variable is meant to describe the cwd where a shiv-managed command was invoked. But the generic name reads like chain-global caller context, and because it is exported it leaks into long-lived descendant processes such as agent sessions. Later tools can then accidentally resolve paths against a stale caller directory.
This showed up while wiring codebase into shiv: an ambient CALLER_PWD from an earlier fold-launched session caused a direct task invocation to target the wrong repo unless overridden explicitly.
Important nuance from follow-up investigation: renaming alone is not sufficient. If shiv-generated shims simply switch from CALLER_PWD to SHIV_CALLER_PWD, long-lived processes launched through shiv (shimmer agent, sessions wake, pi, shells/REPLs/daemons) can still inherit a stale SHIV_CALLER_PWD and recreate the same ambient-context bug under a better name.
Desired direction
Do a deep dive and migrate the ecosystem in one coordinated pass:
- Change shiv-generated shims to use
SHIV_CALLER_PWD for shiv invocation origin.
- Audit all KnickKnackLabs / ricon-family consumers of
CALLER_PWD.
- Update consumers that mean "shiv invocation cwd" to read
SHIV_CALLER_PWD.
- Avoid a long compatibility window if possible; gradual transitions tend to get stale.
- Decide whether any non-shiv meaning for
CALLER_PWD should remain, be scrubbed, or be replaced by a tool-specific variable.
- Add explicit scrub boundaries for long-lived process launchers.
Boundary rule
SHIV_CALLER_PWD is useful for a single command invocation:
cd /some/project
codebase pre-commit
The shim tells codebase: “the user invoked me from /some/project.”
It is risky when launching something long-lived:
shimmer agent
sessions wake
pi
Those processes become a new ambient environment. Launchers should consume the caller cwd if needed, then scrub caller-context variables before exec/spawn:
caller_dir="${SHIV_CALLER_PWD:-${CALLER_PWD:-$PWD}}"
# use caller_dir to choose session cwd / startup dir
unset SHIV_CALLER_PWD CALLER_PWD
exec pi ...
Scrubbing is desirable before launching agents, persistent sessions, shells, REPLs, daemons, or background supervisors. It is not desirable for the immediate shim → task execution path, where the caller context is the point of the variable.
Consumer audit guidance
Do not blindly rename every read.
Search:
rg 'CALLER_PWD|SHIV_CALLER_PWD'
Classify each use:
- shiv shim generation: should set
SHIV_CALLER_PWD="$PWD" unconditionally.
- generated aliases/wrappers: should set
SHIV_CALLER_PWD only for the immediate invocation.
- command target resolution: prefer explicit args/flags/project env vars; use
SHIV_CALLER_PWD only when the command is intended to operate on the invocation cwd.
- tests: may set
SHIV_CALLER_PWD explicitly, but narrowly.
- long-lived launchers: may consume caller cwd, then must unset
SHIV_CALLER_PWD and legacy CALLER_PWD before spawning.
- unrelated generic caller context: should get a tool-specific variable or be removed.
Bad default pattern:
CALLER="${CALLER_PWD:-$(pwd)}"
Better patterns depend on intent:
# immediate shiv invocation context
CALLER="${SHIV_CALLER_PWD:-$PWD}"
# direct command mode: explicit target wins, otherwise current cwd
TARGET="${PROJECT_DIR:-$PWD}"
# long-lived launcher
CALLER="${SHIV_CALLER_PWD:-${CALLER_PWD:-$PWD}}"
unset SHIV_CALLER_PWD CALLER_PWD
exec ...
Why shiv owns this
This is not just shiv being impacted by stale env. shiv creates the contract by emitting CALLER_PWD into every generated shim, so shiv is the right place to define and migrate the convention.
Deep-dive checklist
- Search all repos for
CALLER_PWD reads/writes.
- Classify each use:
- shiv-managed command invocation cwd
- test helper plumbing
- long-lived process launcher
- unrelated generic caller context
- Update shiv shim generation and tests.
- Update affected tools and their tests in coordinated PRs.
- Add regression coverage for stale ambient
CALLER_PWD not affecting shiv-scoped resolution.
- Add regression coverage that long-lived launchers scrub caller-context variables before spawning.
Related
Follow-up from #103 while fixing shiv which resolution for mise-scoped packages.
Problem
shiv-generated shims currently export:
That variable is meant to describe the cwd where a shiv-managed command was invoked. But the generic name reads like chain-global caller context, and because it is exported it leaks into long-lived descendant processes such as agent sessions. Later tools can then accidentally resolve paths against a stale caller directory.
This showed up while wiring codebase into shiv: an ambient
CALLER_PWDfrom an earlier fold-launched session caused a direct task invocation to target the wrong repo unless overridden explicitly.Important nuance from follow-up investigation: renaming alone is not sufficient. If shiv-generated shims simply switch from
CALLER_PWDtoSHIV_CALLER_PWD, long-lived processes launched through shiv (shimmer agent,sessions wake,pi, shells/REPLs/daemons) can still inherit a staleSHIV_CALLER_PWDand recreate the same ambient-context bug under a better name.Desired direction
Do a deep dive and migrate the ecosystem in one coordinated pass:
SHIV_CALLER_PWDfor shiv invocation origin.CALLER_PWD.SHIV_CALLER_PWD.CALLER_PWDshould remain, be scrubbed, or be replaced by a tool-specific variable.Boundary rule
SHIV_CALLER_PWDis useful for a single command invocation:cd /some/project codebase pre-commitThe shim tells
codebase: “the user invoked me from/some/project.”It is risky when launching something long-lived:
Those processes become a new ambient environment. Launchers should consume the caller cwd if needed, then scrub caller-context variables before
exec/spawn:Scrubbing is desirable before launching agents, persistent sessions, shells, REPLs, daemons, or background supervisors. It is not desirable for the immediate shim → task execution path, where the caller context is the point of the variable.
Consumer audit guidance
Do not blindly rename every read.
Search:
rg 'CALLER_PWD|SHIV_CALLER_PWD'Classify each use:
SHIV_CALLER_PWD="$PWD"unconditionally.SHIV_CALLER_PWDonly for the immediate invocation.SHIV_CALLER_PWDonly when the command is intended to operate on the invocation cwd.SHIV_CALLER_PWDexplicitly, but narrowly.SHIV_CALLER_PWDand legacyCALLER_PWDbefore spawning.Bad default pattern:
CALLER="${CALLER_PWD:-$(pwd)}"Better patterns depend on intent:
Why shiv owns this
This is not just shiv being impacted by stale env. shiv creates the contract by emitting
CALLER_PWDinto every generated shim, so shiv is the right place to define and migrate the convention.Deep-dive checklist
CALLER_PWDreads/writes.CALLER_PWDnot affecting shiv-scoped resolution.Related
Follow-up from #103 while fixing
shiv whichresolution for mise-scoped packages.