Sync & git push

Get untracked work back to the host and reach remotes through the host relay with explicit approval

Commits made inside a box land on your host the instant the agent runs git commit. The box's /workspace is a git worktree on branch agentbox/<box-name> against the same .git/ that is bind-mounted from your host, so committed work needs no sync step. See core concepts for the worktree model.

Two things do not cross automatically: untracked files (gitignored artifacts, env files, build output) and anything that needs your credentialsgit push, git fetch, and pull-request operations. SSH keys and tokens never enter the box. This page covers both: pulling untracked work back to the host, and reaching the network through the host relay.

TIP

Tracked commits are already on your host. You only need the tools on this page for untracked files and for anything that talks to a remote (push, fetch, PR ops).

Download your workspace

agentbox download [box] copies /workspace from the box back into your host workspace. It is gitignore-aware by default — it brings down tracked and relevant files while respecting .gitignore.

The [box] argument is optional and defaults to the box for the current project (or pass an index, name, id-prefix, or container). The command prompts for confirmation and shows a change list; --dry-run prints that list and exits without writing, and -y skips the prompt.

# Pull the box workspace back to the host (gitignore-aware), with confirmation
agentbox download

# Preview the change list without writing anything
agentbox download --dry-run

# Target a specific box, skip the prompt
agentbox download 2 -y

Gitignored env and config files are excluded by default. Use --with-env to also pull them, or the narrowing verbs download env and download config to scope to env files or agentbox.yaml only. See CLI commands for all flags.

# Also bring down gitignored env/config files
agentbox download --with-env

TIP

Run agentbox download --dry-run first to see exactly which files would change on the host before committing to the copy.

Sync agent settings between boxes

Installed a skill or plugin inside a box and want it everywhere? agentbox download claude [box] pulls box-installed Claude skills/plugins/agents/commands back to your host ~/.claude (additive — nothing on the host is ever overwritten), and then offers to propagate them to your other boxes: same project, all boxes, or none. download codex and download opencode do the same for their config/auth files. Works on every provider: docker boxes are read from their config volume (even while stopped), cloud boxes from the live box (auto-resuming a paused one).

# Pull new skills/plugins from a box into host ~/.claude, then choose:
#   Propagate to other boxes? › same project / all boxes / no
agentbox download claude mybox

# Non-interactive: pull and push to every box in this project
agentbox download claude mybox --propagate project -y

# Preview only
agentbox download claude mybox --dry-run

Propagation is additive per target: docker boxes get one write to their shared config volume (covering paused ones too), running cloud boxes are pushed over the provider transport, and Claude's plugin registries are merged without touching entries a target already has. Paused cloud boxes are skipped with a note — resume them and re-run to include them. Declining the host write doesn't block propagation: the items are staged from the source box either way.

Cloud boxes (--provider daytona, vercel, hetzner) do a bulk tar pull of /workspace and do not support gitignore-aware change detection or --dry-run. On cloud, the git-aware sync-back path is in-box git push. See Daytona, Vercel, Hetzner.

Copy files

agentbox cp <paths...> is a one-off file copy between host and box, modeled on docker cp. Direction is inferred from which side carries the box: prefix (a : not preceded by /): box:/path sources download, a box:/path destination uploads. The last path is the destination; everything before it is a source.

# Download a single file into the current directory
agentbox cp mybox:/workspace/.env

# Download to an explicit host path
agentbox cp mybox:/etc/foo ./foo

# Upload a file into the box (host path required)
agentbox cp ./local.txt mybox:/workspace/

# Upload a directory (recursive)
agentbox cp ./dir mybox:/workspace/

# Many sources at once into a destination directory
agentbox cp a.txt b.txt src/ mybox:/workspace/dest/

# A shell-expanded wildcard (your shell expands it before agentbox runs)
agentbox cp ./*.log mybox:/workspace/logs/

On download the host path is optional and defaults to the current directory; on upload it is required. With two or more sources the destination must be a directory (end it with /). Directories copy recursively and preserve mode; uploaded files are re-owned to vscode (uid 1000). The box auto-unpauses if needed.

Wildcards are expanded by the shell you type the command in, so cp ./*.log box:/dst/ works from the host and cp box:/workspace/*.log ./ works from inside the box (agentbox-ctl cp toHost). A box-path glob typed on the host can't be expanded (the host shell can't see the box filesystem) — list the files or run it from inside the box.

HEADS UP

Exactly one side must carry the name: prefix, and all sources must be on that one side. agentbox cp ./a ./b (neither side) or agentbox cp box:/a box:/b (both sides) is a usage error, and box sources must all name the same box.

Push & pull via the relay

The box has no git credentials — no SSH keys, no tokens. Anything that hits a remote runs on the host relay, a small process on your machine that executes git with your real SSH agent and ~/.gitconfig, then streams output back into the box.

From the host you run agentbox git <sub> <box>. Inside the box, plain git already does the right thing: a small git shim on the box's PATH transparently routes the four network ops — push, pull, fetch, clone — through the relay (the explicit equivalent is agentbox-ctl git <sub>). Local ops — commit, status, add, log, diff, … — fall through to real git and run normally against the box's checkout. Since commits are already local, push is the op that truly needs the relay; pull is a relay fetch plus a local merge in /workspace.

# Push the box's branch to its remote
agentbox git push 2

# Fetch + merge inside the box's /workspace
agentbox git pull 2

# Switch the box onto main and pull latest (reuse the box for a new task)
agentbox git pull 2 main

# Land the box's branch in your LOCAL repo without publishing it
agentbox git push 2 --host-only
agentbox git push 2 --host-only --as feat/login   # ...under a chosen name

Passing a branch to pull checks it out, then pulls latest — the clean way to rebase a box onto a fresh base and reuse it for a new task. For all flags and the local checkout/status ops, see CLI commands.

Which flags the in-box shim accepts

The relay builds the remote and branch itself from the box's registered worktree, so the shim refuses them as positionals (git push, not git push origin main) and accepts a small set of flags per op:

OpFlags
push--force-with-lease, --tags, --dry-run
pull--ff-only, --prune/-p, --tags/--no-tags
fetch--prune/-p, --prune-tags, --tags/--no-tags, --force/-f, --dry-run
clone--branch <name>, --depth <n>

A clone whose source is unmistakably local (a file:// URL or a filesystem path) needs no host credentials, so it falls through to real git before the gate.

All of push/pull/fetch additionally take --quiet/-q, --verbose/-v, and --progress/--no-progress. Anything else exits 2 with unsupported flag '<x>'. Flags that would rewrite or delete remote refs (--delete, --mirror, push --prune, push --force) stay off the list on purpose — use --force-with-lease for a force-push.

Keep the branch on your machine, not online

git push --host-only makes the box's branch available in your host repo without pushing to any remote — nothing is published online. Use it when you want to git checkout the box's work locally, keep iterating on the host, or review it before deciding whether to publish. It defaults to the box's own branch name; pass --as <branch> to land it under a different name, and --force to allow a non-fast-forward overwrite. From inside the box the agent can do the same with agentbox-ctl git push --host-only. Because nothing leaves the host, this skips the push-approval prompt that a real git push triggers.

For HTTPS remotes, run gh auth login and gh auth setup-git on the host once so plain git push uses gh's token via git's credential helpers — no relay change needed. See teleport a project.

HEADS UP

Plain git push inside the box just works: a git/gh shim routes network ops through the host relay, which runs them with your credentials and asks you to approve writes. Keys and tokens never enter the box. (Use a bare git push, not git push <remote> <branch>.)

On a cloud box, the workspace is a git-bundle copy: git commit lands instantly in the box's own .git. Pushing to your remote runs through the host relay, with your approval.

How the push reaches GitHub — git.pushMode

There are three ways a box's git push can reach your remote:

  • Relay (the default above) — the box asks the host relay to push, and the host runs git push with your own credentials. They never enter the box. Docker boxes always use this (they bind-mount your .git); cloud boxes run it through the relay's cloud poller (a git-bundle pull-back).
  • Lease — when a control plane is configured for a cloud box, the relay/plane leases a short-lived, repo-scoped GitHub-App token and the box pushes directly with it, so the box keeps working with your laptop off.
  • Direct — the box holds a copy of your git credentials and pushes/pulls/signs entirely on its own — no host, no hub. See Independent boxes below.

auto (the default) leases when a control plane is configured for the box, and uses the relay otherwise. Force one with the git.pushMode config key:

agentbox config set git.pushMode relay   # always push through the host relay (your creds)
agentbox config set git.pushMode lease   # always lease a token; box pushes directly
agentbox config set git.pushMode direct  # box holds a copy of your creds (see below)
agentbox config set git.pushMode auto    # default (lease iff a control plane is set)

Only affects cloud boxes. Forcing relay needs a reachable host relay for the box; forcing lease needs a reachable relay/plane with a GitHub App configured.

Independent boxes — --dangerously-with-credentials

The relay and lease modes both keep your credentials off the box — but relay needs your PC on, and lease needs a hosted control plane. For a cloud box you intend to leave running unattended (Hetzner, or a pause/resume box on E2B/Vercel/Daytona), --dangerously-with-credentials copies one git credential into the box so it can push and pull on its own, with your PC off and no hub:

agentbox create --provider hetzner --dangerously-with-credentials
agentbox claude  --provider e2b     --dangerously-with-credentials

At create time it asks — at an interactive prompt — which credential to copy. The choice is a security trade-off:

  • token (recommended) — copies just a GitHub token (read from your git credential helper or gh). The box pushes over HTTPS; a github SSH remote (git@github.com:…) is transparently rewritten to HTTPS, so no SSH key is ever copied. Commits are unsigned. Smallest secret to expose.
  • ssh — copies your SSH private key. The box pushes over SSH and signs commits. This is the riskiest option: use a key dedicated to git, not the key you use to log into other servers.

Inside the box, git push/fetch/pull then run real git against the credentialed remote — the relay is never involved.

Already have a box running? Do the same thing after the fact with agentbox connect <box> --dangerously-git-credentials (Hetzner / DigitalOcean) — the post-create equivalent. It runs the same interactive token-vs-ssh prompt, copies the credential into the live box, and flips it to direct mode. Restart the box's agent session afterward (or open a fresh agentbox shell) so it picks up the new mode — a session already running keeps using the relay until it restarts.

agentbox connect mybox --dangerously-git-credentials   # choose token or ssh
agentbox recover mybox                                  # restart the agent to use it

This copies a real credential into the box

--dangerously-with-credentials places a credential inside the box — where its user has passwordless sudo (no boundary) — and it is captured in any snapshot or checkpoint of it. Only use it for a box you trust to run unattended. For safety this is interactive and foreground only: it requires a real terminal and a human choosing token vs SSH at the prompt. There is deliberately no non-interactive path — no flag value, no env var, no -y — and it is rejected with -i / background runs, so automation and CI can't copy a credential without a person present.

What still needs your PC: agentbox cp/download, checkpoint, and pull-request ops (gh pr create) remain host-relay operations — with the PC off they fail with a clear message rather than hanging. Only git push/fetch/pull are independent. --dangerously-with-credentials is cloud-only (a docker box already runs on your host).

This is about the box's outbound git — it does not open the firewall or make the box reachable. To connect to the box from another device (a phone) with the laptop off, see remote access (agentbox inbound + agentbox connect) — an independent axis you can combine with --dangerously-with-credentials.

Notes: token mode can't sign commits (a token authenticates, it doesn't sign) — pick ssh if you need signed commits. In ssh mode the key must be passphrase-less (there's no ssh-agent in the box); a passphrase-protected signing key leaves signing off so commits never fail.

Pull requests

The relay also proxies the host gh CLI: agentbox git pr <op> <box> from the host, or — inside the box — plain gh pr <op>, which the box's gh shim routes through the relay the same way (the explicit form is agentbox-ctl git pr <op>). gh runs in the host main repo and infers the repo from git remote -v. This needs gh installed and gh auth login on the host.

create is the default op, so agentbox git pr <box> opens a PR for the box's branch. The full op set (view, list, diff, merge, comment, …) lives in CLI commands.

# Open a PR for the box's branch (--head defaults to the box branch)
agentbox git pr create 2 --title "Add feature X" --body "..."

# Inside the box
agentbox-ctl git pr create --title "Add feature X"

Git permissions

By default, a safe subset of relay write ops runs without a prompt (each still logged as a relay event): opening a PR, PR/review comments, re-running CI, pushing to the box's own scratch branch or the branch you put it on with agentbox git checkout/branch/pull, checkpoints, and file copy/download that stays inside the box project folder (non-secret). These can't reach outside the box's project and branch, so the prompt was pure friction. Everything that can — pushing a branch the agent switched to itself, gh pr merge/checkout, and any file transfer that escapes the project folder or touches a secret (.env, keys, credentials) — still raises a host-side approval prompt and proceeds only on a y. Read-only ops (status, pr view/list/diff) never prompt. This is the safe-by-default promise: the agent inside the box can act freely within its own sandbox, a human approves anything that reaches beyond it, and the credentials never leave the host. Set box.autoApproveSafeHostActions=false to prompt for every write op (the older behavior), or box.autoApproveHostActions=true to auto-approve everything including merge/checkout. See core concepts for the security model and configuration for the keys. Env knobs for unattended boxes (AGENTBOX_GH_NO_SUB, …) are documented in CLI commands and background & parallel.

TIP

Running a remote-write command yourself from the host auto-approves via a one-time token — no second prompt. The prompt exists for when the agent inside the box initiates the action.

The agent requests a push or pull request from inside the box; you approve it on the host (here, a gh pr create gated by the relay).

On this page