Work on a GitHub repository in a sandbox
This guide clones a GitHub repository into a sandbox, works on it with git, and opens a pull request. It also connects SSH or Visual Studio Code to the sandbox and runs Claude Code on the repository.
You need:
tritonctlsigned in to your cloud.- The
egress_domainsfeature gate, which your operator turns on.--repoopens egress to GitHub by name. - A NAT gateway and a default route in your VPC, for egress.
- A GitHub token from
gh auth token, or in a local environment variable.
Use a fine-grained GitHub token for the one repository, with only contents and pull request write access.
Where the GitHub token goes
tritonctl never takes the token as a flag value. It reads it from
gh auth token, or from the local variable you name with
--github-token-env <VAR>.
The token goes into the guest only in the environment of one git exec that
moves objects: clone, fetch, push, or ls-remote. Those execs run with
git hooks, the fsmonitor, and custom SSH commands turned off. git reads the
token through a credential helper set for https://github.com only. The token
is not in the command line, the remote URL, a guest file, or the sandbox's
labels and metadata, and the control plane does not store an exec's
environment.
While that exec runs, another process of the same guest user can read its environment. The token's scope is your limit.
Clone and run
tritonctl sandbox create --name app --repo owner/app --branch main
tritonctl sandbox exec app --cwd /work/app -- make test
--repo clones into /work/<NAME> once the sandbox runs. The clone runs as
the sandbox's default user: sandbox for a built-in template, or for your own
template the user its build recorded, else root. It also adds the github network preset: github.com, *.github.com,
*.githubusercontent.com, and codeload.github.com. Add other names your
build needs with --allow-out-domain, for example pypi.org. --net github
adds the same preset without a clone.
Commit, push, and open a pull request
tritonctl sandbox git app -- config user.name "Your Name"
tritonctl sandbox git app -- config user.email you@example.com
tritonctl sandbox git app -- switch -c fix-typo
tritonctl sandbox git app -- commit -am "Fix a typo"
tritonctl sandbox pr app --title "Fix a typo" --draft
sandbox git runs in the only checkout under /work. Give --repo-dir when
there is more than one. Put the git subcommand first. A pull gets no token,
because a checkout can run a filter that the repository names. Run fetch,
then merge.
sandbox pr pushes the current branch to origin and opens the pull request
from your workstation, against the default branch or --base. It prints the
pull request URL. The title defaults to the last commit's subject.
Connect with SSH or VS Code
tritonctl sandbox ssh-config app --install
ssh app.sandbox.triton
ssh-config makes a key pair for this sandbox on your workstation, adds the
public key to the guest's sandbox account, starts sshd on the guest's
loopback address, and pins its host key. The entry's ProxyCommand is
tritonctl sandbox port-forward --stdio, so SSH uses the same authenticated
tunnel as any other port. The sandbox opens no SSH port.
--install writes ~/.ssh/tritonctl/app.sandbox.triton.conf and adds an
Include line at the top of ~/.ssh/config. Without --install, the entry
is printed.
In VS Code, run Remote-SSH: Connect to Host and pick app.sandbox.triton.
The guest allows local port forwarding, which VS Code needs. It refuses
passwords, root, and agent forwarding. scp works with the same host name.
Run Claude Code on the repository
export ANTHROPIC_API_KEY=<ANTHROPIC_API_KEY>
tritonctl sandbox claude --repo owner/app
This uses a sandbox named claude-app, made on first use. The repository is
cloned first, while the sandbox can reach GitHub and not the Anthropic API.
GitHub is then closed, and claude starts in /work/app with access to the
Anthropic API only. claude never gets the GitHub token, so a push from that
sandbox is refused. Copy the work out with fs get, or push from a separate
sandbox.
tritonctl sandbox claude also reads ANTHROPIC_AUTH_TOKEN or
CLAUDE_CODE_OAUTH_TOKEN. ~. at the start of a line detaches and leaves
claude running.
Make many copies of a prepared repository
Build a template with the toolchain. A Dockerfile build needs the
templates_from_dockerfile feature gate, which is off until your operator
turns it on for your tenant. Without it, build from an OCI image with
--image instead. This Dockerfile sets no USER, so commands in
sandboxes made from it run as root.
FROM rust:1
WORKDIR /work
tritonctl sandbox template build rust-dev --dockerfile Dockerfile --follow
tritonctl sandbox create --name app-warm --template rust-dev --repo owner/app
tritonctl sandbox exec app-warm --cwd /work/app -- cargo build
tritonctl sandbox snapshot create app-warm --name built
Fork copies on the same compute node, each with the clone and the build cache:
tritonctl sandbox fork app-warm --from-snapshot built --count 4 --name-prefix app
Or build a template from the snapshot, for new sandboxes on any node:
tritonctl sandbox template build app --from-snapshot app-warm/built --wait
tritonctl sandbox create --template app --net github
A copy made after ssh-config shares the guest's SSH host key. Take the
snapshot before you run ssh-config.
If a step fails
| Symptom | Cause | Fix |
|---|---|---|
403 FeatureDisabled naming egress_domains | Domain egress is not on for your tenant. | Ask your operator. |
| The create is refused for egress | The VPC has no NAT gateway or default route. | Ask the VPC owner to add both. |
gh auth token fails before the create | No GitHub CLI session. | Run gh auth login, or pass --github-token-env. |