Home Directory Management in dify-agent#
The HOME environment variable for shell commands in dify-agent is not owned by the shell layer. It is derived entirely from the RuntimeLease that the runtime backend hands to DifyShellLayer. Understanding this ownership boundary is the key to debugging any home-directory-related failure.
How HOME is constructed#
When a shell command runs, DifyShellLayer._build_shell_command_env() sets env["HOME"] to the home_dir path from the active RuntimeLease.layout. The shell layer never computes or stores a home path itself β it only reads what the runtime backend provides.
For the Local backend, home paths are built by LocalExecutionBindingBackend._home_dir():
{materialized_home_root}/{binding_id}
The materialized_home_root is configured via DIFY_AGENT_LOCAL_SANDBOX_MATERIALIZED_HOME_ROOT (defaulting to /home/dify) . ServerSettings.local_sandbox_materialized_home_root mirrors this field and passes it through to RuntimeBackendSettings during server startup .
The runtime backend validates that the root is an absolute POSIX path at startup; an invalid value raises a ValueError during settings instantiation .
macOS /home compatibility issue#
On macOS, /home is a root-owned symlink to /System/Volumes/Data/home . A non-root dify-agent process cannot create subdirectories there, so any home-directory operation fails with a permission error.
The original hardcoded default of /home was reported in issue #38902 and fixed in PR #38903, which introduced a configurable shell_home_root. In the current architecture this surfaced as the local_sandbox_materialized_home_root setting β set it to a writable path for local macOS development:
DIFY_AGENT_LOCAL_SANDBOX_MATERIALIZED_HOME_ROOT=/tmp/dify-agent-homes
The Operations Guide similarly documents that DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT and related settings replace the older, shell-owned home root: "There is no compatibility setting for the removed shell-provider selector or Shell-owned Home root."
Evolution: shell-owned β runtime-backend-controlled#
| Era | Owner of HOME | Configuration knob |
|---|---|---|
| Original | DifyShellLayer (hardcoded /home/<agent_id>) | None |
| PR #38903 (July 2026) | DifyShellLayer (configurable shell_home_root) | DIFY_AGENT_SHELL_HOME_ROOT env var |
| Current | DifyRuntimeLayer / LocalExecutionBindingBackend | DIFY_AGENT_LOCAL_SANDBOX_MATERIALIZED_HOME_ROOT |
After the refactor, DifyShellLayer no longer configures or validates home roots. Its docstring is explicit: "Commands, files, Home, and cwd come only from DifyRuntimeLayer.lease." The PR-era shell_home_root field and _normalize_shell_home_root() helper are not present in the current codebase β a code search confirms they were superseded when home lifecycle was moved into the runtime backend .
Path isolation (Landlock)#
The runtime grants each agent read-write access exclusively to its own $HOME. On Linux β₯ 5.13, the shellctl-runner child process applies Landlock to enforce this at the kernel level, denying access to other agents' home directories, /tmp, and most host paths . This is why the materialized home root must be a path the shellctl process can reach and write; on macOS, Landlock is not enforced but the permission issue on /home still applies at the filesystem level.
Key files#
| File | Purpose |
|---|---|
runtime_backend/local.py | _home_dir() β computes per-binding home path |
runtime_backend/profile.py | Default roots and RuntimeBackendSettings validation |
server/settings.py | local_sandbox_materialized_home_root server setting |
layers/shell/layer.py | _build_shell_command_env() β reads home_dir from lease |
| Shell Layer user manual | RuntimeLease.layout.home_dir contract description |
| Operations Guide | Full env var reference table |