About Workspaces
Every Scion agent has a dedicated Workspace, mounted at /workspace inside the agent’s container. In worktree-per-agent mode the agent instead works in its worktree under /repo-root (for a repository linked to the local workstation Hub, /repo-root/.scion/agents/<name>/workspace; see Linked git projects); scripts should use $PWD or git rev-parse --show-toplevel. This is where the agent reads code, makes changes, and runs commands.
Scion provides flexible options for how this workspace is backed on your host machine, ranging from isolated git worktrees to direct directory mounts.
Workspace Resolution
Section titled “Workspace Resolution”When you start an agent, Scion determines its workspace based on the following precedence:
-
Explicit Workspace (
--workspaceflag): If you provide a path via--workspace, Scion mounts that directory directly. This works in both Git and non-Git environments. -
Git Worktree (Git repositories): A repository you use with Scion is linked to a Hub on its first command. On the local workstation Hub, each new agent gets a git worktree of your checkout and its own branch (section 2). On a remote Hub, and for projects linked before local worktrees existed, each agent clones the repository’s remote instead. See Linked git projects.
-
Project Root / CWD (Non-Git environments): If you are not in a Git repository, Scion mounts the project root (or current directory for global agents) directly.
1. Explicit Workspaces (--workspace)
Section titled “1. Explicit Workspaces (--workspace)”You can tell Scion exactly which directory to use as the workspace. This is useful for:
- Working on a specific subfolder.
- Using a shared directory across multiple agents.
- Working on a registered git worktree outside the repository root, or a directory outside a non-git project.
Absolute vs. Relative Paths
Section titled “Absolute vs. Relative Paths”The --workspace (or -w) flag accepts both absolute host paths and project-relative paths, distinguished automatically by filepath.IsAbs():
Absolute Paths
Section titled “Absolute Paths”If you specify an absolute host path, Scion mounts that exact directory directly.
# Mount a specific absolute host pathscion start my-agent "run analysis" --workspace /home/user/my-service- Behavior: The specified directory is mounted directly to
/workspace. The Runtime Broker resolves symlinks and checks the path against its Volume Source Restrictions, refusing/, system directories, your home directory, and~/.scionoutside the project’s own workspaces and shared directories (~/.scion/projects/<slug>/workspaces/and~/.scion/projects/<slug>/shared/). - Isolation: None. Changes made by the agent are immediately visible on the host and to any other agents sharing this directory.
- Git: No new worktree or branch is created automatically. In a git project, a workspace in a subdirectory of the repository or outside the repository root must already be a registered git worktree of that repository; a plain subdirectory or an unregistered path outside the repository root is refused at start (see Git that Scion runs on the host).
Relative Paths (Contained Subdirectory Mounts)
Section titled “Relative Paths (Contained Subdirectory Mounts)”If you specify a relative path, it is interpreted as a subdirectory scoped to your project’s logical root (or current working directory). This allows you to confine an agent to a specific subdirectory, such as a package in a monorepo:
# Scope the agent to a project subdirectoryscion start my-agent "fix web bugs" --workspace packages/web- Behavior: Scion resolves the subdirectory path against the project root, performs strict containment checks (preventing directory traversal and escaping via symlinks), and mounts only that subtree to
/workspace. - Isolation: The agent has full containment — it cannot see or access any files or folders outside of that specific subdirectory.
- Support: Supported for directory (non-git) projects — both linked and hub-managed. In a git repository, a subdirectory workspace must be a registered git worktree of that repository; plain subdirectories are refused at start.
- Git-Clone Projects Limitation: Relative
--workspacepaths are not supported for per-agent git (clone-based) projects and will be rejected with an error. For those projects, use an absolute path or omit the--workspaceflag.
2. Git Worktrees
Section titled “2. Git Worktrees”In a repository linked to the local workstation Hub, each new agent gets a git worktree of your checkout at .scion/agents/<name>/workspace (see Linked git projects for the requirements and the checks). Agents imported from a release that ran them without a Hub keep their worktrees at the same place. Each agent has its own isolated working directory and branch, so agents can work on different branches at the same time without touching your own working directory. The rules below describe how those worktrees are set up.
Prerequisites
Section titled “Prerequisites”- Git 2.48.0 or newer is required (for relative path support).
Branch Resolution
Section titled “Branch Resolution”Scion determines which branch to check out in the worktree:
-
Explicit Branch (
--branch,-b):Terminal window scion start my-agent -b feature/login "add logging"- If the branch exists and has a worktree, Scion reuses the existing worktree (see below).
- If the branch exists but has no worktree, Scion creates a new worktree for it.
- If the branch doesn’t exist, Scion creates it (based on current HEAD) and a worktree.
-
Agent Name Matching: If you don’t specify a branch, Scion checks if a branch named after the agent exists (e.g.,
my-agent).- Match Found: It behaves exactly as if you passed
-b my-agent. - No Match: Scion creates a new branch named
my-agentand a corresponding worktree.
- Match Found: It behaves exactly as if you passed
Reusing Existing Worktrees
Section titled “Reusing Existing Worktrees”If you request a branch that is already checked out in another worktree (e.g., by another agent or manually created), Scion detects this.
- Instead of failing or creating a conflict, Scion mounts the existing worktree path.
- A warning is logged:
Relying on existing worktree for branch '...'. With the workstation server it appears in~/.scion/server.log, not in the CLI. - If that worktree is your own checkout (the agent is named after the branch you have checked out), the agent edits your working tree directly.
- This allows multiple agents to collaborate on the same branch/worktree if desired.
- An existing worktree is reused only while its directory is still in place. If git still lists the branch in a worktree that no longer exists, the start fails with an error that names that path; run
git worktree remove "<path>"in the repository and start again. Scion removes only the agent’s own worktree entry, when provisioning and when cleaning up, and does not prune other worktrees (except when a Runtime Broker cannot remove a partly created worktree; it then prunes stale entries so the start can be retried).
3. Non-Git Environments
Section titled “3. Non-Git Environments”In non-git projects (where no .git directory is found):
- Scion defaults to mounting the project root (the directory containing
.scion). - An explicit project path on a Runtime Broker (for example from
scion hub linkorPOST /api/v1/projects/:id/providers) must contain its own.sciondirectory or.scionmarker file (and.scioncannot be a symlink pointing outside the project path); otherwise agent create, start, and restart refuse the path with409 project_path_not_initializedinstead of mounting its parent directory. Initialize the directory withscion initfirst, or createmkdir <path>/.scion. - For global agents, it defaults to the current working directory.
- All agents share the same files. There is no isolation or branching.
4. Hub-Managed Workspaces
Section titled “4. Hub-Managed Workspaces”When a Scion Hub is enabled, workspace strategy changes depending on the project type. The Hub supports three types of remote workspaces:
Hub-Managed Projects (no git repository)
Section titled “Hub-Managed Projects (no git repository)”Hub-Managed projects allow you to create project workspaces directly through the Hub API and Web Dashboard without an external Git repository.
- The Hub automatically initializes a seeded
.scionstructure (projects/<uuid>/.scionon shared workspace storage). - Workspace files live in
projects/<uuid>/workspaceon shared workspace storage (nfs,cloudrun-volume,gke-shared-volume) or~/.scion/projects/<slug>on local storage, and are reached by Runtime Brokers through the same shared workspace storage backend or a co-located Runtime Broker. - You can directly download individual workspace files or generate ZIP archives of entire projects using the Hub API or Web Dashboard, making it easy to export your data.
Git Projects (clone-based, Hub-managed)
Section titled “Git Projects (clone-based, Hub-managed)”Projects created from a remote git repository URL use clone-based provisioning: the agent’s workspace is initialized from the repository at startup.
# Create a git project from a URL (Hub-managed)scion hub project create https://github.com/org/repo.gitHow Git Projects Work
Section titled “How Git Projects Work”- The Hub stores the git remote URL and default branch as project metadata.
- When an agent starts, the Runtime Broker injects
SCION_GIT_CLONE_URL,SCION_GIT_BRANCH, andSCION_GIT_DEPTHas environment variables. - The
sciontool initprocess inside the container uses agit init+git fetchstrategy to provision the workspace into/workspace. This approach handles workspaces that may already contain.scionmetadata or.scion-volumesdirectories, and properly clears stale artifacts before initialization. - A feature branch
scion/<agent-name>is created and checked out automatically.
Project ID Format
Section titled “Project ID Format”Project IDs are always randomly generated UUIDs (v4). A git remote is associated metadata, not identity, so the same repository can back multiple projects, and re-creating a project from the same URL produces a new ID.
Agent Branch Strategy
Section titled “Agent Branch Strategy”Each agent gets its own branch named scion/<agent-name>. This prevents conflicts when multiple agents work on the same repository concurrently.
Shallow Clones & Full Clones
Section titled “Shallow Clones & Full Clones”By default, git projects use a shallow clone with depth=1 for fast startup.
- Full Clones on Startup: If an agent needs full git history for operations like
git logorgit blamefrom the very start, you can configuredepth: 0(or setSCION_GIT_DEPTH=0). TheGitCloneConfigAPI treats a depth of0as an explicit instruction to perform a complete, non-shallow clone. - Unshallowing Later: Alternatively, an agent with a shallow clone (
depth=1) can unshallow itself later inside its session by running:Terminal window git fetch --unshallow
Environment Variables
Section titled “Environment Variables”| Variable | Description | Default |
|---|---|---|
SCION_GIT_CLONE_URL |
URL of the repository to clone. Set by the broker from the project’s clone settings only; a value in agent, settings or harness-config env is ignored | (set by the broker) |
SCION_GIT_BRANCH |
Branch to clone | main |
SCION_GIT_DEPTH |
Clone depth (set to 0 for full clone, omission defaults to shallow depth 1) |
1 |
SCION_GIT_TOKEN_REMOTE |
The project’s git remote, as the Hub recorded it. Set by the broker only | (none) |
Authentication is handled via the GITHUB_TOKEN environment variable, injected from the project’s secrets, a GitHub App installation, or your personal environment through the env-gather flow. The clone uses the token only when the clone URL is HTTPS and names the project’s git remote (the same host and owner/repository as SCION_GIT_TOKEN_REMOTE). A personal token (a user-scoped GITHUB_TOKEN, an agent or storage environment variable, a token collected through env-gather, or a broker/hub-scoped secret) is offered only when the project’s recorded remote is on the GitHub host (github.com, or the host of github_app.api_base_url for GitHub Enterprise), whereas a project-bound credential (the project’s GitHub App installation token or a project-scoped GITHUB_TOKEN secret) applies to the project’s recorded remote on any host. A clone URL that names another host or repository, for example through a scion.dev/clone-url label, is cloned without the token, and no credential helper is configured for it. On every start of an existing clone-per-agent workspace, sciontool init reconciles ~/.gitconfig to remove any unscoped credential.helper and any stale host-scoped helper when no token is offered, and agent-start clones run without host credential helpers, extra HTTP headers, or askpass. The same rule applies to the Kubernetes workspace-provisioning init container.
The clone URL must use https, ssh (including the git@host:path form) or git. Every project repository clone path (on the Runtime Broker host, in sciontool init inside the container, in the Cloud Run runtime, and in the Kubernetes workspace-provisioning init container, including worktree-per-agent starts) checks the URL before any clone or filesystem work and refuses a local path, a file:// or http:// URL, a <transport>::<address> remote-helper form, or a URL starting with - (the repository URL must use https, ssh or git; local paths and other URL schemes are not cloned): the agent is not started. A create request answers HTTP 422, and a start fails with the same fixed message; neither repeats the URL. Clones run with GIT_ALLOW_PROTOCOL=https:ssh:git, protocol.file.allow=never, and http.followRedirects=false.
Linked git projects
Section titled “Linked git projects”This section is the reference for how agents in a git repository on your machine get their workspace; other pages link here.
A repository on your machine becomes a linked project when it links to a Hub: on its first
command against the local workstation Hub (no prompt), or with scion hub link. Run scion init
in the repository first. In a git repository without its own .scion, where the project would
otherwise fall back to the global project (no --global or --project given), scion hub link
and the automatic link refuse with:
this git repository is not a scion project yet; run 'scion init' here first (or pass --global to link the global project)A .scion-less repository inside another scion project is not refused: it links that parent
project, so run scion init in the repository itself.
scion init adds an untracked .scion/ to your checkout and, unless it is already ignored, appends .scion/agents/ to your .gitignore.
On the local workstation Hub: a worktree of your checkout
Section titled “On the local workstation Hub: a worktree of your checkout”A repository that links to the local workstation Hub is registered with the worktree-per-agent
mode. Each new agent then gets a git worktree of your checkout at
.scion/agents/<name>/workspace, on its own branch (see Branch resolution).
The CLI says so when the agent starts:
Using hub, git worktree per agent for repo <remote> (for a checkout linked on this machine, each agent gets a worktree of it under .scion/agents/<name>/workspace; otherwise the runtime broker makes per-agent worktrees of its own clone)- No clone and no token. Nothing is fetched from the remote.
- What the agent sees. The worktree starts from your checkout’s current commit, so commits you have not pushed are visible to the agent; uncommitted changes are not.
- Branches land in your repository. The agent’s branch shows up in
git branch; merge it directly. - The working directory is the worktree, not
/workspace. Your repository is mounted in the container at/repo-root, and the agent starts in/repo-root/.scion/agents/<name>/workspace./workspaceis not mounted for these agents. Scripts and instructions should use$PWDorgit rev-parse --show-toplevelinstead of a hard-coded/workspace. - Deleting an agent deletes its branch, including commits you have not merged, unless you pass
--preserve-branchtoscion delete. - Git 2.48 or newer. The first agent worktree sets
repositoryformatversion=1andextensions.relativeWorktreesin your repository’s git config. From then on, git older than 2.48 cannot read that checkout (it reports an unknown repository extension). - No reincarnate for these agents yet; to rebuild an agent’s home, delete it and start it again.
- This applies to the Runtime Broker inside the workstation server. Kubernetes runtimes are not routed this way.
Before each start, the broker checks the checkout. If a check fails, the start stops; it never falls back to a clone. The CLI shows:
Error: failed to start agent via Hub: runtime broker failure: <reason> (broker code: local_worktree_refused, broker status: 409, request: <id>)where <reason> starts with cannot create a local worktree for this agent: and names the cause
and the fix:
| Cause | Reason (after the prefix) |
|---|---|
| git too old | git >= 2.48.0 required for worktree-per-agent mode (--relative-paths), found <version>; upgrade git on this machine |
| not a git checkout | the project's local path <path> is not in a git checkout; restore the checkout there, or run 'scion hub link' from the project's git checkout |
| repository root unreadable | git could not determine the repository root of the project's checkout at <path>; check that git can read that repository (for example, its ownership and safe.directory setting) |
| no origin | the project's checkout at <repo> has no origin remote, but the hub project's repository is <url>; add it with 'git remote add origin <url>' |
| different origin | the project's checkout at <repo> has origin <url>, but the hub project's repository is <url>; point origin at the hub project's repository, or link this checkout as its own project |
Agents that already have a workspace keep it: agents imported from a release that ran them without
a Hub keep their worktrees at .scion/agents/<name>/workspace, and agents that already have a
clone keep their clone.
Projects linked earlier: still cloning
Section titled “Projects linked earlier: still cloning”The workspace mode is set when a hub project is created and cannot be changed. A repository that
was linked to the local workstation Hub by hand before local worktrees existed keeps cloning (see
the next section) until you re-link it to a new hub project. Running scion hub unlink and then
scion hub link is not enough: it re-attaches the old project. To re-link:
- Finish the project’s agents, or delete them with
scion delete <name>. - Delete the hub project:
scion hub projects delete <name>. This removes the project’s agent records on the Hub for every broker. - In the repository, run
scion hub link(or any agent command, which links automatically). The new project is registered with theworktree-per-agentmode; check withscion hub projects info <name> --format json(the text output does not show labels). When a git checkout that already has a local project directory (~/.scion/project-configs/<slug>__<short-id>) is linked to a new Hub project, agent commands such asscion list,start,stop,resumeanddeleteresolve the Hub project from the link (hub.project_idin the project’ssettings.yaml) rather than the earlier local project ID in.scion/project-id.
On a remote Hub: a clone per agent
Section titled “On a remote Hub: a clone per agent”A repository linked to a remote Hub, or one of the projects above that still clones, gets
clone-based provisioning: each new agent clones the repository’s remote over HTTPS inside its
container, on branch scion/<agent-name>. The Hub enforces one workspace strategy for the
project, whichever broker an agent lands on.
What this means in practice:
- SSH credentials are not used for workspace provisioning. Agents clone via HTTPS using
GITHUB_TOKEN. - A
GITHUB_TOKENis required for private repositories. Set it as a project or user secret on the Hub, or ensure it is present in your local environment (the env-gather flow will collect it; a non-interactivescion startorscion resumesends it only with--send-env, and fails without it naming the missing keys and the--send-envflag):Terminal window scion hub secret set --project=my-project GITHUB_TOKEN ghp_xxxxxxxxxxxx - The CLI will tell you when this mode is in effect:
Using hub, cloning repo https://github.com/org/repo.git
- The agent works from the remote’s state, not from your checkout, and its branch reaches you only after it pushes. Merge agent work via git push and pull request.
To give agents on a remote Hub git worktrees instead of separate clones, create the project with the
worktree-per-agent workspace sharing mode: the broker then
makes a worktree per agent of its own shared clone. The mode is set when the project is created on
the Hub and cannot be changed later.
Git that Scion runs on the host
Section titled “Git that Scion runs on the host”The Runtime Broker and the Hub run git on the host during provisioning clones and in repositories that
agent containers can also write: your linked checkout (when it creates, lists, or removes an agent’s
worktree or checks whether a branch exists), the shared clone of a worktree-per-agent project, and the clone of a shared-workspace
project (including the shared-workspace clone’s local branch-creation fallback when the requested branch is not on the remote, and every step of a shared-workspace pull: reading the current branch, remote URL, and HEAD/FETCH_HEAD commits, fetching, fast-forwarding, and reading the pulled commit list). Before each of these commands in an existing repository,
Scion reads the repository’s config (.git/config, and a worktree’s config.worktree) as data and
refuses the command, naming the key, if the config contains an include/includeIf directive
or any key outside an allow-list, and verifies after the command that the repository config did not change during the run. This is deny-by-default: a key that is not known to be safe stops
the agent start or workspace pull rather than being ignored.
- A repository Scion manages (the shared checkout of a
worktree-per-agentproject, the clone of a shared-workspace project) allows only the keys git and Scion write for it: the core repository format settings,extensions.*, a remote’surl/fetch,branch.<name>tracking, identity,gc.auto,branch.autoSetupMerge. - Your own linked checkout allows those plus a wider set of keys that cannot run a command or
redirect network traffic:
core.autocrlf/eoland similar,pull.*/push.*defaults, a remote’spushurl/tagopt/prune,branch.<name>metadata,color.*,advice.*,rerere.*,status.*,maintenance.*, sparse-checkout toggles,init.defaultBranch, inert git-lfs data keys,gpg.formatanduser.signingKey(signing data only), andsubmodule.<name>.updateonly asnone/checkout/rebase/merge,submodule.<name>.urlonly for anhttps/sshremote. Four more keys are allowed only with a strictly valid value:grep.threads(a non-negative integer),branch.<name>.vscode-merge-base(a valid ref name),remote.<name>.promisor(a boolean) andremote.<name>.partialclonefilter(blob:none,blob:limit=<n>,tree:<depth>,object:type=<type>,sparse:oid=<object id>, or acombine:of those;sparse:pathis refused). A few keys that would run a command are allowed here only because a fixed command-line setting overrides them on every call (core.hooksPath,core.fsmonitor,core.pager,submodule.recurse), so such a repository value never runs a command. - Refused on both (so an agent cannot make the broker’s or your own git run a command): any
credential.*,url.*.insteadOf,http.*,gpg.*program/signing-file keys, any*.program,alias.*,core.sshCommand/editor, a remote’suploadpack/receivepack/proxy, diff/merge command or textconv drivers, non-standardfilter.*drivers, and any key not on the list. If a command is refused, the error names the key; remove it from the repository’s.git/config(orconfig.worktree). - Partial clones: a partial clone made by current git (
git clone --filter=..., which recordsremote.<name>.promisorandremote.<name>.partialclonefilter) is allowed; git then fetches missing objects from that remote’s own URL.extensions.partialClone(written by older git) andindex.sparse(sparse-index checkouts) are not on the allow-list, so host-side git in such a repository is refused and an agent cannot start there. - As defence in depth these commands also run with
LC_ALL=C(dropping any inheritedLC_ALL), with hooks, the file-system monitor and the pager off, signing off (commit.gpgsign/tag.gpgsign/merge.verifySignaturesfalse), theext::transport disabled and thefile://transport allowed only for a top-level operation the user drives directly (protocol.file.allow=user; git’s own indirect uses such as submodule fetches are blocked), submodule recursion off, and theGIT_*environment scrubbed (except the host operator’s own config-file, transport andGIT_ALLOW_PROTOCOLsettings). Note: aGIT_ALLOW_PROTOCOLset by the host operator overrides theprotocol.*.allowpins. - Subcommand-first arguments and discovery mode: host git (
HostGitCommand) refuses argument lists that are empty or start with an option (-), so the first argument is always the git subcommand. When run in a directory with no.gitentry and noGIT_DIRin the environment (discovery mode, including the Runtime Broker’s workspace git probe), host git runs onlyrev-parsein the symlink-resolved directory (withGIT_CEILING_DIRECTORIESset to its parent when ceiling is on) and verifies after the command that the directory still resolves to the same path and gained no.gitorHEADentry. - git-lfs: host-side checkouts take the LFS endpoint from the configured remote, never from a
tracked
.lfsconfig(which an agent could point at an arbitrary server).- A repository Scion manages (the shared checkout and the shared-workspace clone) and every
provisioning clone skip the LFS smudge on the host (
GIT_LFS_SKIP_SMUDGE=1); agents fetch LFS objects in-container. - Your linked checkout pins the endpoint derived from the
originremote URL, with its auth mode pinned tobasic(lfs.<endpoint>.access), when the origin ishttp(s)and the committed.lfsconfigneither names its own endpoint (lfs.url/pushurl,remote.*.lfsurl) nor sets anylfs.<url>.access. If it does either (its objects may legitimately live on a separate server, or it selects an auth mode such asnegotiate), or the origin isssh/scp or absent, the smudge is skipped and a warning names the pointer files and says to rungit lfs pullin the checkout. Scion never contacts the.lfsconfigendpoint. - The git-lfs post-checkout hook does not run; it only marks LFS-lockable files read-only.
- git-lfs’s own config writes are tolerated:
lfs.repositoryformatversion, andlfs.<url>.access(onlybasic/none) andlfs.<url>.locksverifywith an http(s) URL subsection.
- A repository Scion manages (the shared checkout and the shared-workspace clone) and every
provisioning clone skip the LFS smudge on the host (
- Clone URL validation and token binding: when a project is created or updated (
POST /api/v1/projects,PATCH /api/v1/projects/:id), itsgitRepoURL is validated before it is stored: onlyhttps://,http://(only whenSCION_ALLOW_INSECURE_CLONE_HTTP=1is set on the server),ssh://, andgit@host:pathSCP-like URLs with a valid hostname and repository path are accepted (file://,ext::, other transport helpers, bare filesystem paths, embedded credentials, query strings, fragments, and control characters are rejected with400). Credentials are never embedded in a clone URL and never left in a workspace’s.git/config. A git token is supplied only through a credential helper scoped to the clone URL’s host (so it is offered to that host and no other, in particular not to an LFS endpoint), and only for anhttp(s)URL; for any other URL the token is ignored. On project workspace clones and shared-workspace pulls, a personal token is offered only whengitRepois on the GitHub host (github.com, or the host ofgithub_app.api_base_urlfor GitHub Enterprise), while a project-bound credential (the project’s GitHub App installation token or project-scopedGITHUB_TOKENsecret) is offered for the project’s recorded HTTPS remote on any host. The scoped helper also disables any other configured credential helper for the command, so nothing persists the token. On a shared storage layout (server.project_storage), the Hub provisionsshared-plaingit workspaces; if a Runtime Broker reaches its backstop clone path because the Hub’s provisioning sentinel is missing, it offers the agent’s git token only when the clone URL is HTTPS and names the project’s recorded remote (SCION_GIT_TOKEN_REMOTE), and otherwise runs with no token and no host git credentials. - Host credentials: a host-side command that talks to a remote (a clone, a shared-workspace
fetch, a template import) offers no credential of the host’s own. It runs without the host user’s
global and system git config,
~/.netrc, TLS client certificates (http.sslCert/http.sslKey), Kerberos tickets, and ssh agent, keys and ssh config, and with credential helpers, extra HTTP headers and askpass cleared. Without a project git token it runs anonymously; with one, the token is the only credential. Over ssh it offers no host identity and checks the server’s host key strictly against the host user’s and the system’sknown_hosts, without writing them; a project token never authenticates ssh. To trust a private CA, setGIT_SSL_CAINFO(or use the system trust store); for a proxy, sethttps_proxy/no_proxyin the Hub or Runtime Broker environment. - ssh repository URLs on the Hub: a clone or fetch the Hub runs itself (provisioning a
shared-workspace project at project create or project clone, and a shared-workspace pull) refuses a
project clone URL (its
scion.dev/clone-urllabel, elsegitRepo) that uses ssh (ssh://,git+ssh://,ssh+git://orgit@host:path). The refusal comes before any git or filesystem work, as HTTP 422 with a fixed message that names no URL. With a git credential for the project (a project git secret, the GitHub App, or the creator’s GitHub token) the message isa project git secret authenticates https only; use an https repository URL; without one it isan ssh repository URL is not supported for hub-side git; use an https repository URL. Use the repository’shttps://URL. Clones that a Runtime Broker or an agent runs are not affected. - Updating a shared workspace (pull) re-validates the project’s stored
gitRepoURL, verifies that the checkout’soriginremote URL matchesgitRepo(origin remote mismatchotherwise), and fetches fromgitRepo(with the project’s git credential for HTTPS remotes; an SSH URL is refused, as above), then fast-forwards the current branch.
Your own git commands in your checkout are not affected. Scion also mounts the repository’s git metadata into agents so that an agent cannot change what git does for you or for other agents, and checks the repository’s git config before starting the agent:
- Agent-start repository git config check: Before starting an agent in a git repository
(
worktree-per-agent,shared-plain, or an explicit worktree) on Docker, Podman, or the Applecontainerruntime, Scion checks.git/config, the worktree config layers the agent can reach (.git/config.worktreeand.git/worktrees/<name>/config.worktree), and every reachable submodule admin directory (.git/modules/and.git/worktrees/<name>/modules/) and index gitlink against the linked-checkout allow-list above. The agent’s git inside the container reads these layers without the host-side-ccommand-line pins, so settings that name a command or a hook location (core.editor,core.hooksPath,core.fsmonitor,core.pager,core.sshCommand,core.askpass,core.gitProxy,sequence.editor,*.program,alias.*,pager.*, diff and merge driver commands, non-standardfilter.*drivers, a remote’suploadpack/receivepack/vcs, anduploadpack.packObjectsHook) are never given to agents:- On Docker and Podman, the agent reads a private copy of
.git/config. Such settings in.git/configare left out of that copy, the agent starts, and its status message names the keys left out (agent git config: left out core.editor, ... from the agent's copy of .git/config). - The same settings in a
config.worktreelayer or a submodule config, which the agent reads as they are, refuse the start, as they do on the Applecontainerruntime, where the agent reads.git/configdirectly. - Every other key outside the allow-list (
credential.*in a raw layer,url.*.insteadOf,http.*,gpg.*signing-file keys, and so on), andinclude/includeIf, refuse the start everywhere. A refusal names every refused key in one message, with the file to edit for each. A root-level.git/commondiror.git/gitdirfile in any git layout, or an unsafe submodule directory or gitlink (a symlinked module directory, a.gitdirectory inside a submodule work tree, or a gitfile pointing outsidemodules/), also refuses the start. The refusal (agent git config refused: ..., with error codegit_config_refused, HTTP422on synchronous create, start, and restart and on the asynchronous launch phase message) names every refused key (never its value or host path) and the config file to edit (.git/config,config.worktree,the worktree's config.worktree, ormodules/<name>/config/config.worktree), or tells you to remove.git/commondir/.git/gitdiror remove/repair the submodule directory or git link. Put personal git preferences (core.editor, hooks, pager, SSH command, aliases) and credential helpers in your global~/.gitconfigor pass-c/GIT_EDITORper command (GIT_EDITOR=true git ...orgit -c core.editor=true ...), never in the repository config.
- On Docker and Podman, the agent reads a private copy of
In the worktree layouts, the whole .git root is mounted read-only, so an agent cannot create a
root-level file git honours (such as a commondir that would redirect where git reads config, hooks
and refs from). Only the paths an in-container git must write are re-opened read-write: objects/,
refs/, logs/, the git-lfs object store (.git/lfs), and the agent’s own worktree admin directory.
The rerere cache (.git/rr-cache) is re-opened read-write only if it already exists — Scion never
creates it, because creating it would turn on rerere in your own checkout. On docker and podman,
.git/config is served from each agent’s own private, read-only copy in place of the shared one;
the private copy has credential-bearing settings stripped (credential.*, http.extraheader,
http.cookiefile, client TLS key and certificate paths http.sslKey and http.sslCert with or
without a URL subsection while keeping http.sslCAInfo and http.sslCAPath, and plaintext password
keys sendemail.smtppass, imap.pass, git-p4.password, and gitcvs.dbpass; embedded userinfo is
also scrubbed from URL-valued keys remote.*.url/pushurl/lfsurl/lfspushurl,
lfs.url/pushurl, url.*.insteadof/pushinsteadof, http.proxy, remote.*.proxy,
submodule.*.url, bundle.*.uri, fetch.bundleuri, imap.host,
svn-remote.*.url/pushurl/commiturl/rewriteroot, and svn.commiturl, as well as from
branch.*.remote, branch.*.pushremote, and remote.pushdefault when their value is a URL or
remote-helper form rather than a remote name) and is pre-seeded (the agent’s branch
upstream plus push.autoSetupRemote) so that a bare git push exits 0 — without the pre-seed a bare
push fails with “no upstream branch”. (In raw layers that are mounted read-only without redaction —
config.worktree and submodule configs — any of those credential-bearing settings refuses the agent
start.) git push -u origin <branch> exits 0 and reaches the remote
either way; git cannot persist the upstream (the private .git/config is read-only) and prints an
error:, but the push still succeeds.
That copy also disables automatic housekeeping (gc.auto=0, maintenance.auto=false) so routine
commands do not try to write lock files in the read-only root. Personal git preferences inside the
agent go in the agent’s own global git config, which is writable, not in the repository config. On the
Apple runtime agents read the repository’s git config directly (the runtime cannot bind a single
private file), so the private-copy settings above (credential stripping, the push pre-seed, the
housekeeping defaults) do not apply there; keep credentials out of repository git config (use a
credential helper in your global git config). An Apple agent whose repository .git/config holds
any of the credential-bearing settings above is refused at start, naming the key that must be cleared; use a
credential helper in your global git config, or run the project on a runtime that provides the private
config copy.
A shared-workspace git project (agents sharing one checkout) is refused outright on the Apple runtime,
which cannot bind the per-agent private .git/config; use a worktree-per-agent project or a non-Apple
runtime.
Commit, branch creation, fetch, pull, push and rebase work normally. Because the .git root is
read-only, a few operations that write a lock or state file directly in it do not work inside an agent:
deleting a branch or a tag and git fetch --prune (all need packed-refs.lock), git gc /
git pack-refs, and fetching into a shallow clone. These fail cleanly, without corrupting the
repository. git stash still round-trips (the stash ref lives in the writable refs/ overlay), though
it may print a cosmetic packed-refs.lock warning.
This applies to the worktree-per-agent and outside-root layouts, where each agent has its own
worktree. In the shared-workspace layout agents share one working tree and the .git root stays
writable; both the agent-start check and the host-side git controls refuse to run if a root-level
commondir or gitdir is present in the repository.
A workspace in a subdirectory of a repository, or outside the repository root, must be a registered git worktree of that repository (for an outside-root worktree, only /repo-root/.git and /workspace are mounted into the container, not the full repository root). Plain subdirectory workspaces and unregistered workspaces outside the repository root are refused at start, because the per-agent git metadata cannot be mounted for them.
On Docker and Podman, a project .scion that is mounted read-only — one in a registered outside-root
checkout, one in a subdirectory of the workspace, or a nested .scion directory inside the agent’s
own workspace (config-only agents) — must already contain an agents directory.
The runtime masks .scion/agents in the container but does not create it under a read-only mount, so
when it is missing the start is refused; create it once with mkdir <path>/.scion/agents (scion init lists .scion/agents/ in .gitignore) and start the agent again.
On Kubernetes, git projects that share one repository across agents (worktree-per-agent or shared-workspace on NFS) are not supported: use a clone-per-agent workspace, where each agent gets its own clone of the repository, or run the project on a local or Docker Runtime Broker.
5. Project Shared Directories
Section titled “5. Project Shared Directories”Project Shared Directories provide a persistent, mutable storage layer that can be shared between multiple agents within a single project. This is ideal for sharing build artifacts, shared caches, or state files without relying on version control or the Hub database.
Default Scratchpad Auto-Provisioning
Section titled “Default Scratchpad Auto-Provisioning”To ensure that newly created projects have an immediate space for agent file transfers, message attachments, and logs, the Hub can automatically provision a default shared directory named scratchpad upon project creation.
- Auto-Provisioning Toggle: This behavior is controlled by the
project_defaults.default_scratchpadsetting in the Hub’s operational settings (default isON/true). - Inbound Message Attachments: With the
hub.attachment_artifactsexperiment on (on by default wherever the artifact service is ready, including the workstation server’s local artifact store), chat attachments andscion message --attachfiles are delivered directly to each recipient agent’s~/.scion/inbox/<message-id>/, and a copy is placed in the project’sscratchpadshared directory only for project-wide space threads (see Messaging — Attachments for agents). Whenhub.attachment_artifactsis turned off, Scion routes message attachments (including direct messages on the local backend) through thescratchpadshared volume. - Attachment copies expire: Copies of attachments under the scratchpad’s
.attachments/directory and in~/.scion/inbox/are removed aftermessaging.attachment_inbox_retention_days(default 7 days). This covers chat attachments,scion message --attachfiles, chat plugin downloads and terminal drag-and-drop uploads. Downloading an attachment from chat history is not affected.
Managing Shared Directories
Section titled “Managing Shared Directories”You can manage shared directories using the scion shared-dir CLI commands:
# Create a new shared directoryscion shared-dir create <name>
# List shared directories in the current projectscion shared-dir list
# View details about a specific shared directoryscion shared-dir info <name>
# Remove a shared directory (permanently deletes contents)scion shared-dir remove <name>Removing a Shared Directory
Section titled “Removing a Shared Directory”Removing a shared directory deletes its data:
- On a shared backend (
server.project_storage.backendnfs,cloudrun-volumeorgke-shared-volume): removing the declaration through the Hub (Web UI or API) deletes the directory and everything in it from the shared export or volume, which every agent of the project mounts. - On the local backend: unchanged. The directory on the Hub host or the co-located Runtime Broker is deleted, as before.
- The
scratchpaddirectory cannot be removed while the Hub’s project defaultdefault_scratchpadis on. The request is refused with409.
When the Backing Directory Is Created
Section titled “When the Backing Directory Is Created”Creating a shared directory and creating its backing directory on disk are separate steps:
- Local CLI (
scion shared-dir create) creates the backing directory immediately. - Hub (Web UI or API) creates the backing directory when the shared directory is declared, if the Hub can reach the storage it belongs in: the shared export or volume (
server.project_storage.backendnfs,cloudrun-volumeorgke-shared-volume), a hub-managed project’s storage on the Hub host, or the project’s directory on a Runtime Broker running in the same server as the Hub. Otherwise it is created on first use:- when an agent in the project starts on a Runtime Broker. Each Runtime Broker creates the directory locally, or on the shared export or volume.
- when a file is first written or uploaded to it through the Hub.
Until the directory exists, listing the shared directory’s files through the Hub returns an empty list, and reading a file returns not found. Listing or reading never creates the directory.
A write through the Hub only creates the directory in storage the Hub itself can reach: the NFS export, a hub-managed project’s storage on the Hub host, or the project’s directory on a Runtime Broker running in the same server as the Hub. It never creates the directory on a remote Runtime Broker; that copy appears only when an agent of the project starts on that Runtime Broker. For a git project with no co-located Runtime Broker and no NFS storage, a write through the Hub is rejected and creates nothing.
Mounting Shared Directories
Section titled “Mounting Shared Directories”When an agent is created in a project that has shared directories, they are automatically mounted into the agent’s container.
Each shared directory’s mount location depends on its in_workspace setting:
in_workspace: false(default):/scion-volumes/<name>— mounted at the standard volume path, outside the workspace.in_workspace: true:/workspace/.scion-volumes/<name>— mounted inside the workspace tree.
A shared directory is mounted at one of these locations, not both.
By default, shared directories live on the host that runs the agent. In hosted deployments, an operator can set server.project_storage.backend to nfs. Every Runtime Broker then resolves a project’s shared directories (and workspaces) to the same NFS export, so agents on different Runtime Brokers share the same files. A directory that should stay on each node, such as a build cache, is a volumes: entry, not a shared directory; the Runtime Broker checks every volumes: source against its Volume Source Restrictions and refuses paths that resolve into its control files under ~/.scion.
Common Patterns
Section titled “Common Patterns”Shared directories are most useful when several agents in a project need to exchange data outside of version control. The patterns below show typical setups.
Shared Build Caches
Section titled “Shared Build Caches”Agents working on the same project can reuse a compilation cache instead of rebuilding from scratch, dramatically speeding up warm builds.
# Create a shared cache, mounted outside the workspace (default)scion shared-dir create build-cachePoint the toolchain’s cache at the mount. For a Go project, set GOCACHE to the shared path in each agent (for example, in the agent’s shell profile or start command):
export GOCACHE=/scion-volumes/build-cacheThe same approach works for other caches — for example a Bazel --output_base=/scion-volumes/build-cache, or a node_modules/.cache symlinked into the mount. All agents read from and write to the same cache, so the first agent to compile a target populates it for the rest.
Shared Artifacts (Producer/Consumer)
Section titled “Shared Artifacts (Producer/Consumer)”One agent produces build artifacts or data files that another consumes — a build/test or build/deploy split.
scion shared-dir create artifactsThe producer agent writes its output to the mount:
go build -o /scion-volumes/artifacts/myservice ./cmd/myserviceThe consumer agent picks the artifact up from the same path for testing or deployment:
/scion-volumes/artifacts/myservice --run-testsBecause the mount is a plain directory, no Hub round-trip or git commit is needed to hand data between agents.
Shared Context / Knowledge Base
Section titled “Shared Context / Knowledge Base”A directory of reference material — design docs, research findings, or generated context — that every agent can read, and selected agents can write to.
# Read/write for agents that curate the knowledge basescion shared-dir create knowledge --in-workspaceWith --in-workspace, the directory mounts at /workspace/.scion-volumes/knowledge, keeping reference material alongside the code an agent is editing. A research agent writes its findings:
echo "## API rate limits: 100 req/s per token" >> /workspace/.scion-volumes/knowledge/notes.mdA developer agent reads them while working. To make a knowledge base read-only for consumers so they cannot accidentally overwrite curated content, create it with --read-only:
scion shared-dir create knowledge --read-onlyCoordination Files
Section titled “Coordination Files”Lightweight, file-based signalling between agents — status markers, lock files, or simple message passing — without a message broker.
scion shared-dir create coordinationFor example, a build agent signals that a phase is complete by writing a marker file:
# Producer signals completiontouch /scion-volumes/coordination/build.doneA downstream agent waits for the marker before starting its work:
# Consumer waits for the signaluntil [ -f /scion-volumes/coordination/build.done ]; do sleep 5; doneThe same pattern supports simple lock files (create a file to claim a resource, remove it to release) or drop-box message passing (write a request file, poll for a response file). Keep coordination files small and treat them as ephemeral signals rather than durable state.
Web Dashboard File Viewer
Section titled “Web Dashboard File Viewer”You can browse the contents of Shared Directories and view file previews directly from the Hub’s Web Dashboard. In the project view, navigate to the Shared Directories tab to inspect files, view sizes, and review content previews without needing to attach to an agent.
Storage Backends
Section titled “Storage Backends”- Local Workstations: Backed by directories on the host filesystem.
- Kubernetes: Backed by PersistentVolumeClaims (PVCs) with project-scoped lifecycle management, ensuring data persists across pod restarts and can be accessed by any agent in the project.
The cdw Command
Section titled “The cdw Command”Scion provides a helper command, cdw (Change Directory to Worktree), to quickly navigate to an agent’s workspace on your host.
scion cdw <agent-name>- Spawns a new shell inside the agent’s workspace directory.
- Works for both managed worktrees and manual mounts (if resolvable).
Will also take a branch/worktree name outside of scion agents, most useful for getting back to main.
scion cdw <agent-name>Cleanup
Section titled “Cleanup”When you delete an agent:
scion delete <agent-name>- Worktrees: The worktree directory and git’s entry for that one worktree are removed. Scion does not run a repository-wide
git worktree prune, so other worktrees’ entries are left alone. - Branches: By default, the branch is deleted. Use
--preserve-branch(or-b) to keep it. - Explicit Workspaces: Directories mounted via
--workspaceare NOT deleted. Scion only cleans up resources it created.