Projects in a space
Add your GitHub repos as projects, connect them to a space at a branch, tag or commit, and install, update and sync them with your own git.
A project is a GitHub repo: one of yours, or any public one, such as Flask or Express. A space holds projects, each at a ref (a branch, tag or commit), so anyone who installs the space gets the same checkouts. xo keeps both lists in your XO account; the clones are on your machine.
Add a project
xo create project https://github.com/pallets/flask # cloned into ./flask
xo create project https://github.com/expressjs/express # cloned into ./express
xo create project notes # no GitHub remote: ./notes, git init
xo projects # your projectsA GitHub project is called by its repo's name, flask, in every command.
When two of your projects share that name, such as a fork and its upstream,
call it by OWNER/REPO; its folder is then ./OWNER/REPO.
A project made from a plain name can get its repo later:
xo connect notes --repo https://github.com/OWNER/REPOIt is called REPO from then on, and ./notes gets that origin if it has
none and moves to ./REPO.
Put it in a space
xo connect web # a new space entry, web, with no XO Cloud space
xo connect flask web --ref main # Flask in the space web, at main
xo connect express web --ref v5.1.0 # Express in it too, at its tag v5.1.0
xo connect old --id THE_ID # an entry for an XO Cloud space you already have
xo spaces # your spaces, with their projects and refs
xo list # your projects and your spaces togetherxo works out which name is the project and which the space, so
xo connect web flask works too. For a space named like one of your
projects, say space:NAME; project: and space: work in front of any name.
A project you have not added yet
xo connect https://github.com/psf/requests web # adds Requests, then puts it in web
xo install space:web # clones each project into ./web/REPOxo connect PROJECT SPACE adds a project that is not in your projects yet,
as xo create project does but without making its folder, then puts it in
the space, and says so.
- Give the project as
OWNER/REPOor a GitHub URL. A plain name becomes a project with no repo, whichxo connect NAME --repo URLcan give one later. - Nothing is added when the space is missing. If the space then refuses the project (it is full, say), the project stays in your projects.
- A plain name close to one of your projects, most likely a typo, is refused
with the name it is close to, since xo cannot delete a project. To add it
anyway, say
project:NAME. - Put a new plain name first.
xo connect web notesis refused whenwebis one of your spaces, sincenotescould be a space you have not made yet: sayxo connect project:notes space:web, which addsnotesas you typed it.OWNER/REPOand a URL work in either order.
If the first command above stops with connect what? or invalid choice,
your xo is older than this: update it.
Install, update and sync
xo install space:web # ./web/REPO for each project, at its ref
xo update space:web # push each branch with new commits under ./web, then record the refs
xo sync space:web # rebase and push each branch, merge the space's refs, recordThe same three work on one project: xo install project:flask clones it
here (or fetches and fast-forwards it), xo update project:flask pushes its
branch, and xo sync project:flask runs git pull --rebase, then pushes.
-
updateandsyncpush only branches with new commits, so a repo you can't push to is no problem until you commit to it. Without the quirq hub (below) they push to GitHub, so they need push access there. For a repo you can't push to, such as Flask, put your fork in the space in place of Flask (xo connect YOU/flask web) and push to that. Kept beside Flask, the two are calledpallets/flaskandYOU/flask, and the space installs them in./web/pallets/flaskand./web/YOU/flask. -
They use your own git and its login, over https, without submodules.
./SPACE/.xo/state.jsonremembers what was installed. -
updateis refused when the remote is ahead or the space changed since you installed it: runxo sync. A ref its remote does not have is refused too, so nobody else's install breaks. -
synckeeps your changes and the space's. If both changed the same project, it stops and changes nothing. If git cannot rebase a branch cleanly, xo undoes the rebase and says so.
xo never touches a checkout with uncommitted changes, never forces a push,
and refuses a folder whose origin is another repository or carries a login
(https://USER@github.com/...).
Through the quirq hub
Once xo login found the quirq hub, a space's GitHub
projects work through it: the hub is a relay for you and your agents while
the work is under way, and GitHub stays where the work ends up.
- Each checkout gets a second remote,
quirq,quirq://hub.quirq.dev/AGENT/OWNER--REPO.originand everything GitHub sees stay as they are, sogit pushand pull requests work as before. installalso fetches the hub, and takes a branch from there when the hub has it.updatepushes each branch with new commits to the hub, never to GitHub, so Flask needs no fork here.syncrebases on the hub's branch first. Push to GitHub yourself (git push, a pull request) when the work is done.- Anyone can read the hub in this version, so a project GitHub does not show to everyone is refused before anything is sent.
syncnever rewrites a commit GitHub already has: when your branch and the hub's have both moved on and yours holds commits on GitHub, it stops and asks you to merge the hub's in by hand.project:Pcommands stay on GitHub. If the hub's client goes missing afterxo login, a space'supdateandsyncstop and say how to install it.
Next: share a space or a project.
Create a space
Preview a create with --dry-run, then create a Claude Code, Codex or other space on XO Cloud, or make a folder of your git repositories a space on the quirq hub or GitHub.
Share
Invite another XO user to a copy of a space or a project. They see the invite, accept it into their own spaces, or reject it.