A workspace is like a working directory that lives on the Oxen server. You can add, rm, and modify files in a workspace and then commit those changes in bulk, without ever cloning the repository to your local machine.
Under the hood, every workspace is pinned to a specific commit on a branch. All staged changes are computed relative to that commit. Staged changes survive server restarts, but they are not part of the repositoryโs commit history until you commit the workspace, so they can be deleted without leaving a trace.
Why use a workspace?
Reach for a workspace when you want to:
- Edit a repository thatโs too large to clone. Stage changes to a 100GB+ repo without copying it to your machine.
- Bulk-import data without keeping a local copy.
oxen workspace add uploads directly to the server, so you donโt pay the disk cost of writing every file into a local .oxen store first.
- Batch many changes into a single commit. Add, remove, and modify dozens of files server-side, then land them as one atomic commit.
- Let multiple clients contribute to one staged commit. A named workspace can be written to by several processes or users before anyone commits โ useful for workflows like labeling UIs, ingestion services, or agents producing training data.
- Keep a long-lived staging area across multiple commits. Named workspaces persist after commit and fast-forward to the new commit, so the same workspace can be reused over and over.
If youโre working in a repo small enough to clone and just want the normal add โ commit โ push flow, you donโt need a workspace โ see the Version Control guide instead.
Quick start
Add to an existing repo without cloning it
Imagine a repository with 1 million images. Instead of cloning the data, init an empty local repo, point it at the remote, and write directly to a workspace.
oxen init
oxen config --set-remote origin https://hub.oxen.ai/ox/ImageNet-1k
oxen workspace create --name add_image --branch main
# Stage a single file into the images/ directory of the workspace
oxen workspace add /path/to/my_images/image.jpg --directory images/ --workspace-name add_image
# See what's staged
oxen workspace status --workspace-name add_image
# Commit the staged changes to main
oxen workspace commit -m "Add new image to images/ directory" -n add_image -b main
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/ImageNet-1k") # Host defaults to 'hub.oxen.ai'
workspace = Workspace(repo, "extra-images")
workspace.add("new_images/")
status = workspace.status()
print(status.added_files())
workspace.commit("Add new images to dataset")
Bulk-import data into a fresh repo
oxen workspace add never writes data to your local machine โ files stream directly to the remote. This avoids the disk and time cost of add โ commit โ push, which would otherwise copy every file into a local .oxen store first.
oxen init
oxen config --create-remote --host hub.oxen.ai --scheme https --name ox/ImageNet-1k
oxen workspace create # Create a workspace to import the data. This will return a workspace ID
oxen workspace add images/ --workspace-id [WORKSPACE_ID]
oxen workspace commit -m "Import 1 million images" -w [WORKSPACE_ID]
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/ImageNet-1k", files="README.md")
workspace = Workspace(repo)
workspace.add("images/")
status = workspace.status()
print(status.added_files())
workspace.commit("Import 1 million images")
Workspaces can also be driven through the HTTP API โ useful when youโre building a custom client (labeling UI, ingestion daemon, agent, etc.) that needs to write to a repo without shipping the Oxen CLI or Python SDK.
How it works
Every workspace references a specific commit, the same way a branch does. All your staged operations are recorded as a diff against that base commit.
When you commit a workspace:
- Oxen applies your staged diff on top of the workspaceโs base commit to produce a new commit.
- That new commit is added to a target branch on the remote (see Committing changes for how the target is chosen).
- If the target branch has advanced past the workspaceโs base commit, Oxen attempts to merge. Conflicts cause the commit to fail and youโll need to resolve them before retrying.
Because workspaces are commit-scoped, two workspaces created from the same branch at different times can see completely different views of the repo. Thatโs intentional โ it gives you isolation while staging โ but it also means a long-lived workspace can drift from the branch tip and accumulate conflicts.
Creating a workspace
A workspace is created against a remote repository, and optionally against a specific branch.
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/CatDogBBox")
workspace = Workspace(repo, "add-images")
oxen workspace create -w my-workspace-name -b add-images
If no branch is provided, the default branch (usually main) is used.
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/CatDogBBox")
workspace = Workspace(repo)
The workspace is pinned to whatever commit the branch points at when you create it. You can only create workspaces from branches that already exist on the remote.
Named vs. unnamed workspaces
Every workspace has an auto-generated id. You can optionally also give it a human-readable name.
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/CatDogBBox")
workspace = Workspace(repo, name="my-workspace-name")
oxen workspace create -n my-workspace-name
The name matters because of two behavioral differences:
| Unnamed workspace | Named workspace |
|---|
| Lifetime after commit | Deleted | Persists, fast-forwarded to the new commit |
| Best for | One-shot imports, throwaway staging | Long-lived staging, multi-commit or multi-client workflows |
Use a named workspace when you expect to make multiple commits from the same workspace, or when several processes/users will share it. Use an unnamed workspace for one-off imports where you donโt need it to stick around.
Identifying a workspace in CLI commands
Most workspace commands need to know which workspace youโre targeting. You can reference a workspace by either its id or its name:
--workspace-id <id> (short: -w) โ reference by the auto-generated id returned from oxen workspace create.
--workspace-name <name> (short: -n) โ reference by the name you set with --name at create time.
Listing workspaces
List the workspaces on a remote with oxen workspace list.
oxen workspace list -r my_remote # Defaults to `origin` if no remote is provided
Adding files
oxen workspace add streams a fileโs contents directly to the server and stages it on the workspace.
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/CatDogBBox")
workspace = Workspace(repo, "add-images")
workspace.add("/path/to/image.png")
status = workspace.status()
print(status.added_files())
oxen workspace add image.png -w my-workspace-id
oxen workspace status -w my-workspace-id
Unstaging a file
To remove a file youโve staged on the workspace (without touching the base repo), unstage it with oxen workspace rm --staged.
oxen workspace rm --staged image.jpg -w my-workspace-id
Deleting a file from the base repo
oxen workspace rm without --staged stages a deletion of a file that exists in the base repo. When you commit the workspace, that file will be removed from the branch. Use --staged if you only want to unstage a previously added file.
oxen workspace rm image.jpg -w my-workspace-id
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/CatDogBBox")
workspace = Workspace(repo, "add-images")
workspace.rm("image.jpg") # Stages a deletion of image.jpg from the base repo
Committing changes
Commit a workspace to land its staged changes as a new commit on the remote.
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/CatDogBBox")
workspace = Workspace(repo, "add_images")
workspace.commit("adding an image using a workspace", "add_images")
oxen workspace commit -m "adding an image" -w my-workspace-id -b add_images
If you donโt provide a target branch, the commit will be made to a new branch on the remote.
from oxen import RemoteRepo
from oxen import Workspace
repo = RemoteRepo("ox/CatDogBBox")
workspace = Workspace(repo, "my_branch")
workspace.commit("adding an image using a workspace") # No branch is provided, so this will create a new branch
oxen workspace commit -m "adding an image" -w my-workspace-id # No branch is provided, so this will create a new branch
After a successful commit:
- An unnamed workspace is deleted.
- A named workspace is fast-forwarded to point at the new commit, so you can keep using it.
If merge conflicts are detected (because the target branch has advanced past the workspaceโs base commit), the commit will fail.