Page kind: Reference
Coming from git#
Where a SwarmOps operation does what a git command does, so <git verb> runs it, with git's flags where they mean the same. Where the meaning differs the command keeps its own name (land is not merge), and the git verb is refused, exit 2, with one line first in error.hint that names what to type. Nothing looks like git and does something else: so is not a drop-in for the git binary, and a line that ran before git's verbs were read runs as it did.
A git verb that runs is read as the command it stands for (so status is so ws status): the envelope, its op, the help (so status --help) and a usage error are that command's, as the CLI reference gives them. A store has no working tree: status, restore and the bare forms of diff, commit and rebase need a workspace. Their paths are read from the workspace's root, not from the working directory as git's are; below the root a line that names paths is refused. The hints here are written with so; a hint names the program as it was run.
Text output#
Every command prints one JSON envelope unless text is asked for. --human prints text, in git's shape for status, log, diff and commit, and git's own shape flags ask for it too (so status -s, so log --oneline, so diff --stat). For text from every command:
export SWARMOPS_FORMAT=humanClasses#
| Class | Meaning |
|---|---|
| S | The same verb does the same. |
| A | The same verb, read as the SwarmOps command of the same meaning. |
| D | Different on purpose: the verb is refused, and the hint names what to type. |
| N | No such concept: the verb is refused, and the hint says what to do. |
| L | A candidate for later: the notes say what would be built. |
A row can carry two: one form of the verb runs, the others are refused with the hint. op is the operation the example's envelope names; a row without one is refused, and its example prints the hint.
Tier 1: everyday commands#
| git | Class | What to type | op | Example | Hint when refused |
|---|---|---|---|---|---|
git init | S | so init DIR · so ws create NAME | repo_init | so init store2 | — |
git clone | A, L | so clone URL DIR · so ws create NAME | clone_repo | so clone https://remote.invalid/x.git copy | — |
git status | A | so status | ws_status | so status | — |
git add | N | so commit -m MSG [PATH]... | — | so add a.txt | git add: there is no staging area; so commit -m MSG [PATH]... in a workspace takes every change, or the named paths |
git rm | N | so commit -m MSG | — | so rm a.txt | git rm: delete the file in the workspace; so commit -m MSG records it |
git mv | N | so commit -m MSG | — | so mv a.txt b.txt | git mv: move the file in the workspace; so commit -m MSG records it |
git commit | A | so commit -m MSG [PATH]... | ws_commit | so commit -m x | — |
git diff | S, A | so diff FROM TO · so diff | ws_diff | so diff | — |
git log | S, A | so log [REV] -n N --path P | log | so log -1 | — |
git show | S | so show REV · so cat REV:PATH | show | so show main | — |
git branch | D, L | so ref list · so ref set NAME REV --create · so ref delete NAME --expect ID | — | so branch | git branch: so ref list lists refs; so ref set NAME REV --create makes one; so ref delete NAME --expect ID removes one |
git switch | N, L | so ws create NAME --base REV | — | so switch main | git switch: a workspace does not switch; so ws create NAME --base REV makes another |
git checkout | N | so ws create NAME --base REV · so restore PATH... | — | so checkout main | git checkout: so ws create NAME --base REV for another tree; so restore PATH... to drop edits |
git restore | A | so restore PATH... · so ws discard | ws_discard | so restore a.txt | git restore: name the paths, so restore PATH...; so ws discard drops every edit |
git merge | D | so ws land · so land HEAD | — | so merge main | git merge: SwarmOps lands; so ws land from a workspace, or so land HEAD |
git rebase | S, A | so rebase HEAD --onto REF · so rebase | ws_rebase | so rebase | — |
git fetch | S, A | so fetch REMOTE · so fetch | fetch | so fetch | — |
git pull | D | so sync REMOTE --no-push · so rebase | — | so pull | git pull: so sync REMOTE --no-push brings the remote into main; so rebase in a workspace follows it |
git push | S, A | so push REMOTE [REF[:BRANCH]] · so push | push | so push | — |
git remote | S, A | so remote add NAME URL · so remote remove NAME · so remote list · so remote | remote_list | so remote -v | — |
git tag | A, D | so tag · so ref set tags/NAME REV --create · so ref delete tags/NAME --expect ID | ref_list | so tag | git tag: so tag lists; so ref set tags/NAME REV --create makes one; so ref delete tags/NAME --expect ID removes one |
git stash | D, L | so ws snapshot | — | so stash | git stash: so ws snapshot records the edits and leaves the files; nothing pops |
git reset | D | so ws discard [PATH]... · so op undo OP | — | so reset | git reset: so ws discard [PATH]... drops edits; so op undo OP takes an operation back; so ref set moves a ref |
git revert | S | so revert REV --reason TEXT | revert | so revert main --reason x | — |
git cherry-pick | N, L | so land HEAD --base BASE | — | so cherry-pick main | git cherry-pick: not built; so land HEAD --base BASE lands one change's range |
git blame | L | so history REV:PATH | — | so blame a.txt | git blame: not built yet (M7); so history REV:PATH lists the changesets that touched a path |
git grep | N | so cat REV:PATH | — | so grep x | git grep: search the files of a workspace; so cat REV:PATH reads one at a revision |
git config | N | so whoami · so remote | — | so config user.name | git config: identity is --as or SWARMOPS_AGENT (so whoami); the store is --repo or SWARMOPS_REPO; remotes are so remote |
git reflog | A | so reflog NAME · so op log | ref_log | so reflog main | git reflog: so reflog NAME lists a ref's moves; so op log every operation; nothing expires |
Notes on tier 1#
git init: Makes a store, no working tree;DIRis required. Thenso ws create NAME.-b,--bareare not taken.git clone: A: positionalDIR(=--into). A store and no files, asgit clone --bare; thenso ws create NAME. Later:--ws NAME, a new flag: a working tree in the same step.git status:-s,-b,-sb,--short,--branchask for the text listing. Paths from the workspace's root.git add: No staging area: a commit takes every change, or the named paths.git rm: Delete the file in the workspace; the next commit records it.git mv: Move the file in the workspace; the next commit records a delete and an add.git commit:so commit --changes FILEkeeps its meaning (the JSON change list). Takes every change, new files included unless an ignore file names them (git's-aleaves new files out);-ais accepted. Paths from the workspace's root. No--amend(D:so op undo, then commit again), no editor.git diff: Lists the changed paths by default;-pfor the patch.--stat,--name-status,-U<n>. Paths by--path P, not-- P, from the workspace's root. NoA..B, no--staged.git log: First parents, frommainunless REV is given, also inside a workspace: its own commits areso log IDwith the headso ws infogives. A:--oneline,-<n>. No--graph,--author,--since, ranges.git show: The changeset and its changed paths, no patch.git show REV:PATHisso cat REV:PATH.git branch: A ref list also holdstags/andremote/; there is no current branch. Later: abranchverb once FORMAT 2 branches map to git refs (with M11).git switch: A workspace never switches; make another. Later: unscheduled.git checkout: Not offered under this name (git itself split it).git restore: At least one path, as in git. A file never committed is deleted (git leaves an untracked file). Paths from the workspace's root; below the root the line is refused..is no path (exit 2). No--staged,--source. Every edit:so ws discard.git merge: One squashed changeset onto the target by compare-and-swap; no merge commit.git rebase: Store form: one squashed changeset, no ref moves. Workspace form: the workspace follows its target;--continue,--abort,--ontothere. No-i.git fetch:mainnever moves on a fetch. No--all,--prune.git pull:synclands onto the remote's head and movesmain; a workspace follows by its own rebase.git push: Sendsmainunless REF is named;mainandrelease/*only. Compare-and-swap, fast-forward only; no--force,-u,--tags.git remote:so remote,so remote -vlist;so remote rmremoves. Norename,set-url.git tag: FORMAT 2 stores. Lightweight only; a tag never moves.git stash: Records the edits as a changeset and leaves the files; nothing pops. Later: unscheduled.git reset:mainmoves forward only. A ref:so ref set NAME REV --expect ID.git revert: Lands the inverse;--sincefor a range. The reason is required.git cherry-pick: One change's range lands as one changeset. Later: M24 (rewriting with lineage).git blame: The changesets that touched a path. Later: M7.git grep:rgorgrepin a workspace.git config: There is no configuration command.git reflog: A name is required (no store-level HEAD). Every operation:so op log.expire,delete,existsare refused with the hint: nothing expires.
Tier 2: commands scripts and CI use#
| git | Class | What to type | op | Example | Hint when refused |
|---|---|---|---|---|---|
git rev-parse | D | so resolve REV · so ws info | — | so rev-parse main | git rev-parse: so resolve REV gives the full id; so ws info a workspace's head and path |
git rev-list | D | so log REV -n N · so ancestry FROM TO | — | so rev-list main | git rev-list: so log REV -n N; so ancestry FROM TO |
git ls-files | D | so ls REV[:PATH] | — | so ls-files | git ls-files: so ls REV[:PATH] |
git ls-tree | D | so ls REV[:PATH] --depth N | — | so ls-tree main | git ls-tree: so ls REV[:PATH] --depth N |
git cat-file | D | so cat REV:PATH · so blob get ID · so blob has ID | — | so cat-file -p main | git cat-file: so cat REV:PATH; so blob get ID; so blob has ID |
git hash-object | D | so blob put FILE | — | so hash-object a.txt | git hash-object: so blob put FILE |
git describe | N | so tag | — | so describe | git describe: not built; so tag lists the tags |
git for-each-ref | D | so ref list [--prefix P] | — | so for-each-ref | git for-each-ref: so ref list [--prefix P] |
git show-ref | D | so ref list | — | so show-ref | git show-ref: so ref list |
git symbolic-ref | N | so ws info | — | so symbolic-ref HEAD | git symbolic-ref: there are no symbolic refs; so ws info gives a workspace's head and target |
git update-ref | D | so ref set NAME REV --expect ID | — | so update-ref main main | git update-ref: so ref set NAME REV --expect ID, or --create; so ref delete; so ref txn |
git merge-base | S | so merge-base REV ONTO · so ancestry FROM TO | merge_base | so merge-base main main | — |
git name-rev | N | so ref list | — | so name-rev main | git name-rev: not built; so ref list gives each ref's changeset |
git ls-remote | D | so fetch REMOTE · so ref list --prefix remote/REMOTE/ · so sync status REMOTE | — | so ls-remote | git ls-remote: so fetch REMOTE, then so ref list --prefix remote/REMOTE/; so sync status REMOTE |
git diff-tree | D | so diff FROM TO --format names · so show REV | — | so diff-tree main | git diff-tree: so diff FROM TO --format names; so show REV |
git worktree | A, D | so worktree list · so ws create NAME [--path DIR] [--base REV] · so ws list · so ws delete NAME | ws_list | so worktree list | git worktree: so ws create NAME [--path DIR] [--base REV]; so ws list; so ws delete NAME |
git clean | N | so ws discard PATH... | — | so clean -f | git clean: so ws discard PATH... drops the named paths' edits, new files included; without a path, every edit |
git archive | N, L | so git export PATH | — | so archive main | git archive: git init --bare PATH, so git export PATH, then git archive there |
git bisect | N, L | — | — | so bisect start | git bisect: not built |
git shortlog | N | so log | — | so shortlog | git shortlog: so log, counted by author_agent |
Notes on tier 2#
git ls-files: A workspace's files are plain files.git ls-tree: JSON entries, not<mode> <type> <id>\t<path>.git describe: Unscheduled.git symbolic-ref: No symbolic refs; no store-level HEAD.git merge-base: Along first parents, with what REV changed.--is-ancestor:so ancestry FROM TO.git worktree: git names a path, SwarmOps a workspace name.git archive: Later: M25 (archives).git bisect: Later: unscheduled.
What is not done#
| Not done | Why | What to do |
|---|---|---|
A drop-in for the git binary (alias git=so, --porcelain, -z, git's exit codes, GIT_DIR) | The JSON envelope is the machine contract; two contracts would have to be kept alike for ever. | Scripts read the envelope. Stock git works against a store through swarmops serve, and so git export PATH writes a real git repository. |
An index: add, rm --cached, restore --staged, diff --staged, commit -p | Agents commit whole changes; a second state between the files and the store is one more thing to lose in a crash. | so commit -m MSG PATH... commits the named paths only. |
| Interactive rebase, an editor for messages | No terminal is assumed; a land squashes to one changeset anyway. | so rebase in a workspace; -m everywhere; so op undo OP to take a step back. |
checkout | Two meanings in one verb. | so ws create NAME --base REV; so restore PATH.... |
merge with a merge commit, --force on push, moving main back | The trunk moves forward only, by compare-and-swap. | so land HEAD, so revert REV --reason TEXT. |
git's revision words HEAD, ^, A..B, A...B, @{upstream} | No store-level HEAD; first-parent history. | main, a ref name, an id prefix, ~N, NAME@{N}; so ancestry FROM TO for a range. |
stash pop, cherry-pick, blame, bisect, describe, archive, grep | Not built. | The hint of each, in the tables above. |
| git verbs as MCP tools | The tools are the operations; an alias adds nothing an agent can call. | The existing tools (ws_status, ws_commit, …). |
| Text by default | One rule for people and agents: an agent under a pseudo-terminal is never surprised. | --human, SWARMOPS_FORMAT=human, or a shape flag (-s, --oneline, --stat). |
CLI reference
Every command of swarmops and so, its short form: the same program by a shorter name. This page and the command pages are generated from the command line's…
Error codes
A failed command prints an envelope whose error names a stable E_* code, the process exit code (exit) and whether running the operation again can succeed…