Summary
gh-aw currently assumes GitHub Copilot CLI state and MCP config live under /home/runner/.copilot, and some setup paths also assume ownership should be reset to runner:runner.
That works on GitHub-hosted runners, but it makes self-hosted Linux runners harder to use when the runner service account and home directory do not match the GitHub-hosted default layout.
Today the workaround is to create a compatibility shim that manufactures /home/runner/.copilot and bridges the actual runner account back to that location. It would be much easier to operate gh-aw on self-hosted infrastructure if upstream supported a configurable or runtime-derived Copilot config path instead of hardcoding /home/runner.
Analysis
From tracing the current implementation, the /home/runner assumption appears in multiple places:
Hardcoded path / ownership assumptions
-
actions/setup/sh/install_copilot_cli.sh
- sets
COPILOT_DIR="/home/runner/.copilot"
- resets ownership with
sudo chown -R runner:runner "$COPILOT_DIR"
-
actions/setup/sh/start_mcp_gateway.sh
- checks for and writes to
/home/runner/.copilot
-
actions/setup/js/convert_gateway_config_copilot.cjs
- writes MCP config to
/home/runner/.copilot/mcp-config.json
-
pkg/workflow/copilot_engine_execution.go
- sets:
GH_AW_MCP_CONFIG=/home/runner/.copilot/mcp-config.json
XDG_CONFIG_HOME=/home/runner
-
pkg/workflow/copilot_mcp.go
- emits workflow steps that create
/home/runner/.copilot
- renders MCP config into
/home/runner/.copilot/mcp-config.json
There is also mirrored setup logic in github/gh-aw-actions, so any fix here likely needs to stay aligned with the synced action scripts.
Current behavior
On self-hosted runners, gh-aw currently expects:
- a usable
/home/runner/.copilot directory
- MCP config at
/home/runner/.copilot/mcp-config.json
- ownership repair back to a literal
runner:runner
That means environments that use a different service account/home path need extra compatibility work even though the actual requirement is just “Copilot CLI needs a writable config/state directory”.
Expected behavior
gh-aw should work on self-hosted Linux runners without requiring:
- a literal
runner user
- a literal
/home/runner home directory
- compatibility symlinks just to satisfy internal path assumptions
It should either:
- derive the Copilot config/state location from the runtime environment, or
- support a documented override while preserving
/home/runner as the default for backward compatibility
Proposed implementation plan
Please implement the following changes.
1. Centralize Copilot config path resolution
Create a single source of truth for the Copilot config/state path used by Copilot-related workflow generation and setup scripts.
Suggested behavior:
- default remains
/home/runner/.copilot/mcp-config.json for backward compatibility
- allow override via environment/config rather than hardcoding everywhere
- derive the Copilot directory from the config file path instead of duplicating string literals
A good target is to make GH_AW_MCP_CONFIG the canonical config file path and derive:
- Copilot config dir =
dirname(GH_AW_MCP_CONFIG)
- Copilot home / XDG config root = parent of
.copilot
This keeps one canonical value instead of scattering /home/runner/.copilot across Go, shell, and JS.
2. Remove hardcoded runner:runner ownership repair
Update Copilot CLI install/setup scripts so ownership repair uses the current runtime user/group instead of assuming a literal runner account.
For example, the shell logic should use the executing account’s identity rather than:
The fix should preserve the original intent:
- repeated AWF/chroot runs may leave
.copilot root-owned
- the directory should be repaired back to the account that will run Copilot CLI next
3. Update setup scripts to honor the resolved path
Update the following paths to use the centralized resolved value instead of /home/runner/... literals:
actions/setup/sh/install_copilot_cli.sh
actions/setup/sh/start_mcp_gateway.sh
actions/setup/sh/convert_gateway_config_copilot.sh (if still relevant)
actions/setup/js/convert_gateway_config_copilot.cjs
These scripts should:
- write MCP config to the resolved path
- create the resolved directory if needed
- avoid checking for
/home/runner/.copilot directly when determining Copilot mode
4. Update workflow generation in Go
Update the Copilot workflow generation logic so it does not bake /home/runner into generated workflows unnecessarily.
Relevant areas:
pkg/workflow/copilot_engine_execution.go
pkg/workflow/copilot_mcp.go
Goals:
- preserve today’s default behavior for existing users
- allow self-hosted environments to override without patching generated workflows by hand
- avoid setting
XDG_CONFIG_HOME=/home/runner unconditionally if an override is present
5. Add regression tests
Please add tests covering both the default path and an overridden/non-default path.
Suggested coverage:
Go tests
- generated workflow still defaults to
/home/runner/... when no override is set
- generated workflow uses the resolved/overridden path when provided
- no tests depend on a literal
runner user
Script tests
- config conversion writes to the resolved location
- ownership repair targets the current runtime identity rather than
runner:runner
- scripts work when the Copilot directory is not under
/home/runner
6. Update docs
Please update the relevant documentation to explain self-hosted runner behavior and any new override/default behavior.
Suggested docs areas:
- self-hosted runner guidance
- Copilot/MCP troubleshooting docs
- any docs that currently present
/home/runner/.copilot/mcp-config.json as the only supported location
The docs should make it clear that:
/home/runner remains the default for backward compatibility if that is retained
- self-hosted users can use a different runtime account/home layout
- a compatibility shim should not be required when the path is configured correctly
7. Keep gh-aw-actions sync in mind
Because the setup scripts are mirrored/synced into github/gh-aw-actions, please ensure the final implementation path accounts for that sync process so the released action behavior stays consistent with gh-aw.
Acceptance criteria
This issue is complete when all of the following are true:
gh-aw no longer requires a literal runner user for Copilot setup
gh-aw no longer requires /home/runner to exist on self-hosted runners
- Copilot MCP config path can be overridden or derived from runtime configuration
- default behavior remains backward compatible for existing GitHub-hosted usage
- tests cover both default and non-default path/user scenarios
- docs explain the behavior clearly for self-hosted runners
Non-goals
This issue is not asking to change the default GitHub-hosted runner behavior.
It is specifically asking to remove the hard requirement on the GitHub-hosted-style user/home layout so self-hosted runners can work without compatibility shims.
Summary
gh-awcurrently assumes GitHub Copilot CLI state and MCP config live under/home/runner/.copilot, and some setup paths also assume ownership should be reset torunner:runner.That works on GitHub-hosted runners, but it makes self-hosted Linux runners harder to use when the runner service account and home directory do not match the GitHub-hosted default layout.
Today the workaround is to create a compatibility shim that manufactures
/home/runner/.copilotand bridges the actual runner account back to that location. It would be much easier to operategh-awon self-hosted infrastructure if upstream supported a configurable or runtime-derived Copilot config path instead of hardcoding/home/runner.Analysis
From tracing the current implementation, the
/home/runnerassumption appears in multiple places:Hardcoded path / ownership assumptions
actions/setup/sh/install_copilot_cli.shCOPILOT_DIR="/home/runner/.copilot"sudo chown -R runner:runner "$COPILOT_DIR"actions/setup/sh/start_mcp_gateway.sh/home/runner/.copilotactions/setup/js/convert_gateway_config_copilot.cjs/home/runner/.copilot/mcp-config.jsonpkg/workflow/copilot_engine_execution.goGH_AW_MCP_CONFIG=/home/runner/.copilot/mcp-config.jsonXDG_CONFIG_HOME=/home/runnerpkg/workflow/copilot_mcp.go/home/runner/.copilot/home/runner/.copilot/mcp-config.jsonThere is also mirrored setup logic in
github/gh-aw-actions, so any fix here likely needs to stay aligned with the synced action scripts.Current behavior
On self-hosted runners,
gh-awcurrently expects:/home/runner/.copilotdirectory/home/runner/.copilot/mcp-config.jsonrunner:runnerThat means environments that use a different service account/home path need extra compatibility work even though the actual requirement is just “Copilot CLI needs a writable config/state directory”.
Expected behavior
gh-awshould work on self-hosted Linux runners without requiring:runneruser/home/runnerhome directoryIt should either:
/home/runneras the default for backward compatibilityProposed implementation plan
Please implement the following changes.
1. Centralize Copilot config path resolution
Create a single source of truth for the Copilot config/state path used by Copilot-related workflow generation and setup scripts.
Suggested behavior:
/home/runner/.copilot/mcp-config.jsonfor backward compatibilityA good target is to make
GH_AW_MCP_CONFIGthe canonical config file path and derive:dirname(GH_AW_MCP_CONFIG).copilotThis keeps one canonical value instead of scattering
/home/runner/.copilotacross Go, shell, and JS.2. Remove hardcoded
runner:runnerownership repairUpdate Copilot CLI install/setup scripts so ownership repair uses the current runtime user/group instead of assuming a literal
runneraccount.For example, the shell logic should use the executing account’s identity rather than:
runner:runnerThe fix should preserve the original intent:
.copilotroot-owned3. Update setup scripts to honor the resolved path
Update the following paths to use the centralized resolved value instead of
/home/runner/...literals:actions/setup/sh/install_copilot_cli.shactions/setup/sh/start_mcp_gateway.shactions/setup/sh/convert_gateway_config_copilot.sh(if still relevant)actions/setup/js/convert_gateway_config_copilot.cjsThese scripts should:
/home/runner/.copilotdirectly when determining Copilot mode4. Update workflow generation in Go
Update the Copilot workflow generation logic so it does not bake
/home/runnerinto generated workflows unnecessarily.Relevant areas:
pkg/workflow/copilot_engine_execution.gopkg/workflow/copilot_mcp.goGoals:
XDG_CONFIG_HOME=/home/runnerunconditionally if an override is present5. Add regression tests
Please add tests covering both the default path and an overridden/non-default path.
Suggested coverage:
Go tests
/home/runner/...when no override is setrunneruserScript tests
runner:runner/home/runner6. Update docs
Please update the relevant documentation to explain self-hosted runner behavior and any new override/default behavior.
Suggested docs areas:
/home/runner/.copilot/mcp-config.jsonas the only supported locationThe docs should make it clear that:
/home/runnerremains the default for backward compatibility if that is retained7. Keep
gh-aw-actionssync in mindBecause the setup scripts are mirrored/synced into
github/gh-aw-actions, please ensure the final implementation path accounts for that sync process so the released action behavior stays consistent withgh-aw.Acceptance criteria
This issue is complete when all of the following are true:
gh-awno longer requires a literalrunneruser for Copilot setupgh-awno longer requires/home/runnerto exist on self-hosted runnersNon-goals
This issue is not asking to change the default GitHub-hosted runner behavior.
It is specifically asking to remove the hard requirement on the GitHub-hosted-style user/home layout so self-hosted runners can work without compatibility shims.