diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
index bcfc1a483538ed..2220df0a51d395 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
@@ -137,7 +137,6 @@ public class CommandEnvironment {
   private final DelegatingDownloader delegatingDownloader;
   private final RemoteAnalysisCachingEventListener remoteAnalysisCachingEventListener;
   private final ImmutableList.Builder<IdleTask> idleTasks = ImmutableList.builder();
-  private final ResourceManager resourceManager;
 
   private boolean mergedAnalysisAndExecution;
 
@@ -234,8 +233,7 @@ public void exit(AbruptExitException exception) {
       CommandExtensionReporter commandExtensionReporter,
       int attemptNumber,
       @Nullable String buildRequestIdOverride,
-      ConfigFlagDefinitions configFlagDefinitions,
-      ResourceManager resourceManager) {
+      ConfigFlagDefinitions configFlagDefinitions) {
     checkArgument(attemptNumber >= 1);
 
     this.runtime = runtime;
@@ -256,7 +254,6 @@ public void exit(AbruptExitException exception) {
     this.timestampGranularityMonitor = new TimestampGranularityMonitor(runtime.getClock());
     this.attemptNumber = attemptNumber;
     this.configFlagDefinitions = configFlagDefinitions;
-    this.resourceManager = resourceManager;
 
     // Record the command's starting time again, for use by
     // TimestampGranularityMonitor.waitForTimestampGranularity().
@@ -358,6 +355,9 @@ public void exit(AbruptExitException exception) {
         value = clientEnv.get(name);
       }
       if (value != null) {
+        if (workspace.getWorkspace() != null) {
+          value = value.replace("%bazel_workspace%", workspace.getWorkspace().getPathString());
+        }
         repoEnv.put(name, value);
         repoEnvFromOptions.put(name, value);
       }
@@ -715,7 +715,7 @@ public WorkspaceInfoFromDiff getWorkspaceInfoFromDiff() {
   }
 
   public ResourceManager getLocalResourceManager() {
-    return resourceManager;
+    return ResourceManager.instance();
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CommonCommandOptions.java b/src/main/java/com/google/devtools/build/lib/runtime/CommonCommandOptions.java
index 8041263d3a6374..e2948b036998e4 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CommonCommandOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CommonCommandOptions.java
@@ -542,7 +542,9 @@ public String getTypeDescription() {
           "Specifies additional environment variables to be available only for repository rules."
               + " Note that repository rules see the full environment anyway, but in this way"
               + " configuration information can be passed to repositories through options without"
-              + " invalidating the action graph.")
+              + " invalidating the action graph. The string <code>%bazel_workspace%</code> in a"
+              + " value will be replaced with the absolute path of the workspace as printed by"
+              + " <code>bazel info workspace</code>.")
   public List<Map.Entry<String, String>> repositoryEnvironment;
 
   @Option(
diff --git a/src/test/shell/bazel/starlark_repository_test.sh b/src/test/shell/bazel/starlark_repository_test.sh
index dfcecdb94eee3b..de5d343f4992a7 100755
--- a/src/test/shell/bazel/starlark_repository_test.sh
+++ b/src/test/shell/bazel/starlark_repository_test.sh
@@ -880,6 +880,49 @@ EOF
       || fail "Expected unrelated action to not be rerun"
 }
 
+function test_repo_env_workspace_interpolation() {
+  setup_starlark_repository
+
+  cat > test.bzl <<'EOF'
+def _impl(ctx):
+  result = ctx.execute(["my_tool"])
+  if result.return_code != 0:
+    fail("my_tool failed ({}, PATH = {}): {}".format(result.return_code, ctx.os.environ["PATH"], result.stderr))
+  ctx.file("out.txt", result.stdout)
+  ctx.file("BUILD", 'exports_files(["out.txt"])')
+
+repo = repository_rule(
+  implementation = _impl,
+)
+EOF
+  cat > BUILD <<'EOF'
+genrule(
+  name = "repoenv",
+  outs = ["repoenv.txt"],
+  srcs = ["@foo//:out.txt"],
+  cmd = "cp $< $@",
+)
+EOF
+  if "$is_windows"; then
+    local repo_env_path="%bazel_workspace%/repo_tools;$PATH"
+  else
+    local repo_env_path="%bazel_workspace%/repo_tools:$PATH"
+  fi
+  cat > .bazelrc <<EOF
+common --repo_env=PATH="$repo_env_path"
+EOF
+
+  mkdir -p repo_tools
+  cat > repo_tools/my_tool.bat <<'EOF'
+echo Hello from my_tool
+EOF
+  cp repo_tools/my_tool.bat repo_tools/my_tool
+  chmod +x repo_tools/my_tool
+
+  bazel build //:repoenv &> $TEST_log || fail "Failed to build"
+  assert_contains "Hello from my_tool" `bazel info bazel-bin 2>/dev/null`/repoenv.txt
+}
+
 function test_repo_env_inverse() {
   # This test makes sure that a repository rule that has no dependencies on
   # environment variables does _not_ get refetched when --repo_env changes.