If you find this add-on useful, please star it on GitHub — stars show appreciation and help maintainers know their work matters.
This DDEV add-on installs GitHub Copilot CLI inside the DDEV web container and automatically shares your host GitHub CLI and Copilot configuration — including authentication and Copilot settings — with no additional setup required.
Once installed, running copilot inside ddev ssh or ddev exec uses a writable copy of your host configuration and a token derived from your host gh authentication.
gh) installed and authenticated on the host — the host is where the token is resolved, so gh auth status must succeed thereddev add-on get e0ipso/ddev-assistant-copilot
ddev restart
After installation, commit the .ddev directory to version control.
$PATH for every shellnpm install -g @github/copilot into ~/.local/bin (warns and continues if npm install fails)~/.config/gh/ and ~/.copilot/ trees are mounted read-only under ~/.cred-seed/, then mirrored into the writable container directories on every restart:
~/.config/gh/ — GitHub CLI configuration and authentication (e.g. hosts.yml)~/.copilot/ — Copilot CLI configuration (e.g. config.json, hooks)COPILOT_GITHUB_TOKEN and GH_TOKEN on shell startup, while preserving any token explicitly injected into the container environment. Interactive shells (.bashrc, .profile) and non-interactive shells (/etc/bash.env via BASH_ENV) resolve the token dynamically instead of storing the literal value.gh and copilot are on $PATH for both interactive shells (ddev ssh) and non-interactive commands (ddev exec)GitHub CLI stores your token in the OS keychain by default — macOS Keychain,
GNOME Keyring (Secret Service) on Linux, Windows Credential Manager. It writes a
plaintext oauth_token: into ~/.config/gh/hosts.yml only as a silent fallback
when no keychain is reachable, such as on a headless server or WSL.
A container cannot reach the host keychain. So copying ~/.config/gh/ into the
container and running gh auth token there only ever works on hosts that took
the plaintext fallback. That is why forwarding used to succeed on headless Linux
and fail on macOS and Linux desktops, and why selecting an account with
DDEV_ASSISTANT_COPILOT_GH_USER could not help: the token was not in the file at
all.
This add-on resolves the token on the host instead:
pre-start hook runs gh auth token on the host, honouring the configured
hostname and user, and writes the result to
~/.ddev-assistant-copilot/<project>/token with mode 600.~/.cred-seed/auth/.COPILOT_GITHUB_TOKEN already present in the container environmentgh auth token — still correct for hosts that legitimately
use plaintext storageThe token is refreshed on every ddev start, so a rotated or revoked token is
picked up by a restart.
The token is deliberately kept out of DDEV’s environment plumbing:
web_environment, so it never appears in docker inspect.ddev/.env.web or any file inside the project directory, so it
cannot be committed/etc/bash.env, .bashrc, or .profile600 file under $HOME, outside the projectNote that inside the web container, PHP runs as the same user as copilot, so
anything reachable by Copilot CLI is reachable by your application code. The
practical benefit over an environment variable is that a file is not dumped by
phpinfo(), Xdebug stack traces, or a Symfony/Whoops error page. If that
residual exposure matters for your project, use ephemeral mode below.
To keep no token at rest at all, set this in
.ddev/config.assistant-copilot.yaml:
web_environment:
- DDEV_ASSISTANT_COPILOT_EPHEMERAL_TOKEN=true
ddev start then stages no token. Instead, run Copilot through the host command:
ddev copilot
This resolves a fresh token from the host keychain for that invocation and
removes it when the session exits. The trade-off is that plain copilot inside
ddev ssh is left unauthenticated and will prompt you to log in.
ddev copilot works in the default mode too, where it simply refreshes the token
before starting the session.
The add-on ships with this non-secret default:
web_environment:
- DDEV_ASSISTANT_COPILOT_GH_HOSTNAME=github.com
# - DDEV_ASSISTANT_COPILOT_GH_USER=your-github-username
Use this when you have multiple GitHub accounts, such as a personal account and
a work account, authenticated for the same host. Uncomment and set
DDEV_ASSISTANT_COPILOT_GH_USER in your installed
.ddev/config.assistant-copilot.yaml to tell the add-on which account should
provide COPILOT_GITHUB_TOKEN.
If either variable is empty or removed, the add-on does not pass that option to
gh auth token, allowing GitHub CLI’s default account/host selection to apply.
# Run Copilot CLI with a token resolved fresh from the host keychain
ddev copilot
# Open a shell with Copilot CLI available
ddev ssh
copilot
# Run Copilot CLI non-interactively
ddev exec copilot --version
# GitHub CLI is also available, and authenticated
ddev exec gh auth status
You can install Copilot CLI and gh inside a DDEV container yourself. This add-on automates the parts that are easy to get wrong or forget:
| This add-on | Manual setup | |
|---|---|---|
| GitHub CLI | Installed in the image layer via official apt repo; on $PATH for every shell |
Must install and re-install after image rebuilds |
| Copilot CLI | npm install -g @github/copilot on every start into ~/.local/bin |
Must run npm install manually; easy to lose on restart |
| Config approach | Seeds writable container ~/.config/gh/ and ~/.copilot/ from your host config on restart — zero setup if you already use gh and Copilot on the host |
Must copy or symlink config by hand; stale container files persist |
| Authentication | Token resolved on the host, so it works whether or not gh used the OS keychain; exported as COPILOT_GITHUB_TOKEN and GH_TOKEN without writing literal tokens into shell startup files, web_environment, or the project directory |
Copying ~/.config/gh only works on hosts without a keychain; otherwise you must export a token manually in every shell type |
| Non-interactive shells | BASH_ENV=/etc/bash.env ensures ddev exec gets PATH and token |
ddev exec often misses PATH and env vars |
| Mount safety | Pre-start hook ensures host config directories exist before Docker bind-mounts them | Bind-mount fails silently or blocks start if dirs are missing |
| Tests / CI | BATS integration tests, GitHub Actions CI matrix (DDEV stable + HEAD), daily scheduled runs | No automated verification |
This add-on does one thing: install GitHub Copilot CLI into your DDEV container and share your existing host configuration. Nothing else.
Contributed and maintained by @e0ipso
If you find this add-on useful, please star it on GitHub — stars show appreciation and help maintainers know their work matters.