Skip to content

Org Workspace

Code name: org-workspace

Clones the repos of a GitHub org next to your project and keeps a VS Code multi-root workspace file up to date. Add it to one project’s devcontainer.json and the other repos are there when the container is created.

Use it when several repos of the same org are developed together. For a single repo it does nothing useful.

Also included automatically: repairs broken host paths in your git config and restores your SSH commit-signing key on every attach, on both local and cloud containers, with nothing to set up on your end — see helpers4-common for how it works.

{
  "features": {
    "ghcr.io/helpers4/devcontainer/org-workspace:1": {}
  }
}

With no options, it takes the org from your project’s origin remote and clones every repo you can see, except forks and archived ones. Each repo goes to /workspaces/<repo> and a <org>.code-workspace file is created in your project’s root folder. Open it once with File > Open Workspace from File…. VS Code cannot open it for you from inside a container.

To pick the repos yourself, or to skip some:

"ghcr.io/helpers4/devcontainer/org-workspace:1": {
  "repos": "typescript,devcontainer,action",
  "exclude": "website"
}

A fixed repos list gives the same result on every rebuild, even when the org adds or removes repos.

OptionTypeDefaultDescription
orgstring""GitHub org (or user) to clone from. Empty means the owner of your origin remote.
reposstring""Comma-separated repos to clone. When set, autoDiscover is ignored.
autoDiscoverstring"true""true": public and private repos, no forks, no archived. "false": clone nothing. Or a list of categories, e.g. "public,fork": public, private, internal, fork, archived.
excludestring""Comma-separated repos to skip, whether they come from repos or autoDiscover.
generateCodeWorkspacebooleantrueCreate or update the .code-workspace file.
codeWorkspaceNamestring""File name. Empty means <org>.code-workspace.
  1. At build, install.sh installs the script and makes /workspaces writable for your user.
  2. When the container is created, the script:
    • clones each repo into a Docker volume (helpers4-org-workspace-${devcontainerId}, mounted at /mnt/h4org-workspace) and links it from /workspaces/<repo>. The clones live in the volume, so a rebuild keeps your local branches and uncommitted work;
    • updates the .code-workspace file to match what is in /workspaces.

A failed clone, or no access to a repo, prints a warning and the rest carries on. The script always exits 0, because a failing lifecycle command would stop the ones after it.

Three kinds of folders live in /workspaces, and only one is managed on disk:

FolderOn diskIn the .code-workspace file
Your project (where devcontainer.json is)never touched, and its repo is never cloned again, even under another folder namealways listed (.)
A link into the volume, made by this featurecreated and removed to follow the repo listlisted while it exists
Anything else: a folder you mounted, cloned or copied therenever touched, and not cloned overlisted while it is a git checkout

So a repo you mount yourself at /workspaces/<repo> wins over the clone. It stays even when the repo leaves the list: you mounted it, you remove it.

The entries that point at /workspaces/<name> follow the disk: a git checkout there is added, and an entry whose folder is gone or excluded is removed. Other entries (outside /workspaces, uri entries) and your settings are left alone.

Each org repo is named with an icon for its status, the first that applies:

IconStatus
📦archived
🔀fork
🔒private
🏢internal
🌍public

A name you wrote yourself is kept. Only a missing name, the plain repo name or a name with one of these icons is updated, so the icon follows when a repo changes status. Folders outside the org keep their plain name.

A repo that is no longer wanted (you excluded it, or it was archived or deleted upstream) loses its link in /workspaces and its entry in the workspace file. Its clone is deleted only when git confirms nothing would be lost: no uncommitted or ignored files (except node_modules), no stash, no commit missing from the remote. Otherwise the clone stays in the volume and a warning says so.

Nothing is unlinked when the list of repos looks incomplete: when gh repo list fails, when it returns nothing, or when nothing is left once exclude and your project’s repo are taken out.

A repos list is taken as it is: a typo in it (typscript) unlinks the repo you meant, as if you had removed it.

  • GitHub only, and one org per project.
  • The repos are cloned when the container is created. A repo added to the org, or archived, shows up (or goes) after the next rebuild.
  • A .code-workspace file with comments is left as it is, because it cannot be edited safely. Otherwise the file is rewritten the way VS Code writes it: tabs, no final newline.
  • Needs an authenticated gh, which github-dev provides.

Should work, since gh is already authenticated there and named volumes behave the same. Not tested in a real Codespace yet.

  • OS: Linux (Debian/Ubuntu-based images)
  • Architectures: amd64, arm64
  • v1.1.0: Folder names get a status icon (public, private, internal, fork, archived). The workspace file now matches what is in /workspaces: an archived repo no longer stays in it after a rebuild, and dead entries are removed. autoDiscover with two visibilities no longer lets the third one in. Your project’s repo is never cloned again under another folder name. Mounted folders are listed, and gh errors are shown.
  • v1.0.1: autoDiscover defaults to "true". New exclude option. The script no longer fails the container when something goes wrong, and /workspaces is writable at build time. It now runs when the container is created instead of at every start, and removes repos that are no longer wanted.
  • v1.0.0: Initial release.