These guides are primarily for agent readers. They explain how agents use Sails. If you are a person, start at sails.app or Add Sails.

Sync with GitHub

Sails has two version-control commands. Mixing them up is the usual failure.

JobCommand
Checkpoint, branches, reviews, publish in Sailsrepo …
Talk to GitHub / GitLab / similar remotesgit …

There is no system git. git is a small bridge to external remotes. After clone / pull, autosave checkpoints the tree into Sails. Run git push when the external remote should update. Do not run repo save as a ritual.

.git/ lives in the session and is not stored with repo. Scratch git state is discarded when the session ends. Store the remote URL (and the ssec_… id, never the plaintext) so the next session can git remote add again.

Run git from inside the repository workspace ($HOME or a folder under it). That is where autosave and the bridge agree on which files exist.

Done looks like

git status is clean. git log --oneline shows your commit. git push succeeds. On GitHub the branch has that commit. Sails still uses repo for publish; you did not treat git as the Sails VCS.

Worked example: clone, edit, push (HTTPS PAT)

Job: repository owner pulls https://github.com/org/app.git into ~/app, changes a file, pushes main.

Clone / fetch / pull / push are owner-only. Local status / add / commit / rebase need write access to the workspace.

1. Store the PAT for the git host

Do not put ghp_… in a file. secret open requires --origin, and the origin has to match the host git talks to. Git over HTTPS talks to https://github.com, not https://api.github.com. A token stored for the API origin will not authenticate a clone. See Store a secret.

secret open --origin https://github.com github-pat

Expected output (shape):

Open this URL to submit the secret:
  https://…/secrets/intake/…
Intake: 8c1e…

Open the URL, sign in as a repository owner, paste the PAT, submit. Then:

secret poll 8c1e…
# prints: ssec_a1b2c3d4...

Do not pass --wait from bash_exec. You would not see the URL until the wait ends. Print, then secret poll.

2. Clone

git clone https://github.com/org/app.git app --depth 1 --token ssec_a1b2c3d4...

--token ssec_… is the preferred HTTPS auth. You can also put ssec_… in the URL userinfo (https://x-access-token:ssec_…@github.com/org/app.git); it is resolved, then stripped. The HTTPS username defaults to x-access-token. Pass --username NAME when a host wants something else.

Expected: a directory app/ with the default branch. Autosave then checkpoints that tree into Sails.

cd app
git config user.email agent@example.com
git config user.name "Sails agent"

git config only supports user.name and user.email. Anything else fails with git config: only user.name and user.email are supported.

3. Save the remote once

A fresh clone is enough to push in the same session. To keep the auth with the remote (and for a later git init workspace), add it with the token id:

git remote add origin https://github.com/org/app.git --token ssec_a1b2c3d4...
git remote
# origin

git remote stores the URL and the token id, never the secret plaintext. Change the URL with git remote set-url origin URL. Drop it with git remote remove origin.

4. Edit, commit, rebase, push

# edit files under app/ …
git status --porcelain
git diff
git add -A
git diff --cached
git commit -m "update README"
git fetch origin --token ssec_a1b2c3d4...
git rebase origin/main          # or: git pull --rebase origin main --token ssec_…
git push origin main --token ssec_a1b2c3d4...

Expected after the commit (ids differ):

$ git status
On branch main
nothing to commit, working tree clean
$ git log --oneline -n 1
eedec5f update README

On conflict: edit the files, git add <paths>, git rebase --continue. To drop the commit that conflicts, git rebase --skip. To give up, git rebase --abort. Interactive rebase (-i) is not available.

First push of a new branch:

git checkout -b fix-typo
# edit, add, commit …
git push -u origin fix-typo --token ssec_a1b2c3d4...

git push --force exists. Use it only on a branch you own; it rewrites history on GitHub.

SSH deploy key

Store the private key PEM as a platform secret, then pass its ssec_… id with -i on every remote op:

git clone git@github.com:org/app.git app --depth 1 -i ssec_deploy_key
git remote add origin git@github.com:org/app.git -i ssec_deploy_key
git fetch origin -i ssec_deploy_key
git push origin main -i ssec_deploy_key

SSH remotes (git@host:org/repo.git or ssh://…) require -i ssec_…. Host keys use the same per-repo TOFU pins as ssh, so a GitHub host you already pinned for SSH to a host is trusted here too.

Cloudflare Artifacts

Artifacts remotes use short-lived art_v1_… bearers. One-shot clone with the header form:

git -c http.extraHeader='Authorization: Bearer art_v1_…' clone \
  'https://….artifacts.cloudflare.net/git/…/package-….git' pkg

-c http.extraHeader='Authorization: Bearer …' is the only -c setting the bridge accepts. It maps to --token. art_v1_… also works directly as --token, or embedded in the URL userinfo.

When you will reuse the remote or push later, wrap the bearer in a secret (paste only the art_v1_… value, no ?expires=). Set --origin to the Artifacts host from the clone URL, scheme + host only:

printf '%s' "$ART_TOKEN" | secret set --origin https://….artifacts.cloudflare.net --stdin
# prints: ssec_…
git clone 'https://….artifacts.cloudflare.net/git/…/package-….git' pkg --token ssec_…

Artifacts hosts default to username x (not GitHub's x-access-token).

Live usage

git help prints the full usage. Subcommands do not take --help (git clone --help fails with unsupported flag '--help').

git [-c http.extraHeader='Authorization: Bearer <token>'] <command> …
git init [--bare] [directory]
git clone <url> [directory] [--depth N] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git status [--porcelain]
git log [--oneline] [-n N]
git diff [--cached] [refs…] [--] [paths…]
git show <object>
git add [-A|--all] <path>…
git commit -m <message> [--allow-empty]
git branch [<name>] | git branch -d <name>
git checkout [-b] <branch|ref>
git merge <branch> | git merge --abort | git merge --continue
git rebase <upstream> | git rebase --continue|--abort|--skip
git config user.name|user.email <value>
git remote | git remote add <name> <url> [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git remote remove <name> | git remote set-url <name> <url>
git fetch [remote] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git pull [--rebase] [remote] [branch] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git push [-u] [--force] [remote] [branch] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
FlagWhereWhat it does
--token ssec_… / art_v1_…clone, remote add, fetch, pull, pushHTTPS auth
-i ssec_…sameSSH deploy key (required for SSH remotes)
--username NAMEsameHTTPS username. Default x-access-token, or x on Artifacts hosts
--depth NcloneShallow clone. Use it on big repos
-upushSet upstream for a new branch
--forcepushOverwrite the remote branch
--rebasepullRebase instead of merge
--porcelainstatusMachine-readable status for scripts
--oneline, -n NlogShort history
--cacheddiffStaged changes
--allow-emptycommitCommit with no changes

Not supported: interactive rebase, submodules, LFS, stash, tags, system git hooks, any git config key besides user.name / user.email.

WhoOps
Repository ownerclone / fetch / pull / push
Write access to the workspacelocal init, status, add, commit, branch, checkout, merge, rebase, …

Limits: remotes must pass the same network policy as curl / ssh (private/reserved IPs blocked). Clone/fetch unpacked size is capped around 250 MiB.

Failure modes

What you seeWhat it meansWhat to do
clone / push deniedRemote ops are owner-onlyAn owner runs them, or elevate that goal
secret: secret open requires --origin URLYou ran secret open github-pat with no originsecret open --origin https://github.com github-pat
Clone with a valid ssec_… still fails authSecret origin is https://api.github.com (or another host)Git talks to https://github.com. Store the PAT for that origin
git: git clone: unsupported flag '--help'Subcommands have no --helpgit help
git: unknown or unsupported subcommand 'stash' (or 'tag')Not in the bridgeCommit to a scratch branch instead of stashing. Tag on GitHub
git: git rebase: interactive rebase (-i) is not supportedNo -iPlain git rebase <upstream>, then --continue, --skip, or --abort
git: git config: only user.name and user.email are supportedOnly those two keys existSet only user.name and user.email
git: there is no rebase in progressYou ran --continue / --skip / --abort with nothing to resumeCheck git status; start the rebase first
git: could not find '…/sails-git/…' to statYou ran git outside the repository workspace (for example /tmp)Work under $HOME
You ran repo save to sync GitHubrepo does not talk to GitHubgit push (owner)
You ran git to publish a sitePublish tracks the repo branch headPublish a site
SSH remote without -iDeploy key is required-i ssec_… on clone/fetch/pull/push
.git gone next sessionNot saved with repogit remote add again; the files in $HOME are still there if autosave checkpointed them
Clone too large~250 MiB unpacked cap--depth 1, or split the repo on the remote side
Private/reserved IPSame block as curl / sshUse a public Git host
You committed ghp_ or a PEMWrong storesecret unset is not enough. Rotate at GitHub, secret open --origin https://github.com, use the new ssec_… with --token / -i

See Store a secret for ssec_…. Sails checkpoints stay on repo.