{"id":47801532,"url":"https://github.com/afajl/mob","last_synced_at":"2026-04-03T17:04:01.209Z","repository":{"id":47109827,"uuid":"259882432","full_name":"afajl/mob","owner":"afajl","description":"Console tool for remote mob programming","archived":false,"fork":false,"pushed_at":"2024-05-06T04:40:05.000Z","size":29419,"stargazers_count":14,"open_issues_count":2,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-05-29T13:46:01.156Z","etag":null,"topics":["cli","mob","mob-programming","mob-programming-timer","rust","timer"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/afajl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-04-29T09:31:23.000Z","updated_at":"2023-08-20T11:39:58.000Z","dependencies_parsed_at":"2026-04-03T15:03:53.945Z","dependency_job_id":null,"html_url":"https://github.com/afajl/mob","commit_stats":{"total_commits":121,"total_committers":3,"mean_commits":"40.333333333333336","dds":0.1900826446280992,"last_synced_commit":"ae8f36ad707ed2e984675391ed3919e20d6cbd46"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/afajl/mob","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afajl%2Fmob","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afajl%2Fmob/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afajl%2Fmob/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afajl%2Fmob/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/afajl","download_url":"https://codeload.github.com/afajl/mob/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afajl%2Fmob/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31364613,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T15:19:21.178Z","status":"ssl_error","status_checked_at":"2026-04-03T15:19:20.670Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","mob","mob-programming","mob-programming-timer","rust","timer"],"created_at":"2026-04-03T17:04:00.524Z","updated_at":"2026-04-03T17:04:01.194Z","avatar_url":"https://github.com/afajl.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n![mob](https://github.com/afajl/mob/raw/main/assets/logo.png)\n\nMob is a console tool to work in a remote mob (or pair) with git.\n\n* Handover code fast between drivers\n* Remembers order of drivers\n* [Keeps track of state](#how-it-works) (working, waiting for next, stopped) to eliminate risk of conflicts and lost work\n* Use any branch as base\n\n![mob screen](https://github.com/afajl/mob/raw/main/assets/screen.gif)\n\n\n\n\u003c!-- Run :UpdateToc to update --\u003e\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n* [Installing](#installing)\n    * [Cargo](#cargo)\n    * [Manually](#manually)\n* [Usage](#usage)\n    * [FAQ](#faq)\n        * [How do I remove all traces of `mob` from a repo?](#how-do-i-remove-all-traces-of-mob-from-a-repo)\n        * [Where is the configuration stored?](#where-is-the-configuration-stored)\n        * [How do I show current status?](#how-do-i-show-current-status)\n        * [Work duration is set to 15 but we must stop for a meeting in 7 minutes](#work-duration-is-set-to-15-but-we-must-stop-for-a-meeting-in-7-minutes)\n* [Hooks](#hooks)\n* [How it works](#how-it-works)\n* [Inspiration and other tools](#inspiration-and-other-tools)\n\n\u003c!-- vim-markdown-toc --\u003e\n\n## Installing\n\n### Cargo\nInstall [rust](https://www.rust-lang.org/tools/install) and run:\n```bash\ncargo install remotemob\n```\n\n### Manually\nDownload the [latest\nrelease](https://github.com/afajl/mob/releases/latest) and unpack it to somewhere in your\nPATH.\n\n## Usage\n\u003e Note: It's safe to try mob! It prints all git commands it runs and if you decide that it's not for you can [remove all traces](#how-do-i-remove-all-traces-of-mob-from-a-repo).\n \n- `mob start` creates a new feature branch or syncs the branch from the\n  previous driver. \n- `mob next` commits all changes to the feature branch and hands over to the next driver.\n- `mob done` stages all changes on the feature branch for commit on the base branch (normally main).\n\n![mob graph](https://github.com/afajl/mob/raw/main/assets/graph.svg)\n\nRun `mob` for help on more commands.\n\n### FAQ\n#### How do I remove all traces of `mob` from a repo?\n1. Run `mob done` to remove the mob branch. Either commit the\nchanges or run `git reset HEAD --hard` to discard changes.\n2. Run `mob clean` to remove the `mob-meta` branch.\n3. Delete `~/.mob` if you don't want to use `mob` anymore\n\n#### Where is the configuration stored?\nConfiguration local to you is stored in `~/.mob`. Configuration\nfor a repository is stored in an orphan branch named `mob-meta`.  \n`mob start` creates all configuration needed to run. It is always\nsafe to run `mob clean` to remove the repository config and start\nfresh.\n\n#### How do I show current status?\nRun `mob status`\n\n#### Work duration is set to 15 but we must stop for a meeting in 7 minutes\nRun `mob start 7`\n\n\n## Hooks\nYou can add hooks to your configuration in `~/.mob` to notify you\nwhen your turn is over or to take over screen sharing when you\nstart. \n```language: toml\n...\n[hooks]\nafter_start=\"take_screen.sh\"\nafter_timer=\"say 'mob next NEXT_DRIVER'\"\n```\n\n\nHooks are executed by a `sh` and can contain two\nvariables:\n- `CURRENT_DRIVER`: Always the name you configured in `~/.mob`\n- `NEXT_DRIVER`: Next driver or `anyone` if you are the first in\n  a session. It is empty on all `before_*` hooks.\n\nThe available hooks are:\n- `before_start`: Run as soon as possible when you run `mob start`, before checking that it's your turn \n   or that your working directory is clean.\n- `after_start`: Right after you've started a session with `mob start` but before the timer started. \n   This is a good hook for taking over the screen. \n- `after_timer`: Run when your turn ended. The first time you run\n   `mob start` it tries to find commands to play a sound and show\n   a desktop notification to populate this hook.\n- `before_next`: Before running mob next, `NEXT_DRIVER` is not available.\n- `after_next`: Before running mob next, `NEXT_DRIVER` is either\n   a name or `anyone`. \n- `before_done`: Before the squashing and deleting branches.\n- `after_done`: After done has been run, `NEXT_DRIVER` is not available.\n\n\n## How it works\n`mob` uses an orphan branch called `mob-meta` to save session\nstate and settings. You can view the session content with `mob\nstatus [-r]` and delete it with `mob clean`.\n\n```javascript\nSession {\n    drivers: Drivers(\n        [\n            \"Paul\",\n            \"Leo\",\n            \"Ella\",\n        ],\n    ),\n    branches: Branches {\n        branch: \"mob-session\",\n        base_branch: \"main\",\n    },\n    settings: Some(\n        Settings {\n            commit_message: \"mob sync [skip ci]\",\n            work_duration: 10,\n        },\n    ),\n    state: Working {\n        driver: \"Ella\",\n    },\n}\n```\n\nThe session can be in 3 different states:  \n\n![mob states](https://github.com/afajl/mob/raw/main/assets/state.svg)\n\n\n## Inspiration and other tools\nInspiration for this tool comes from [Remote mob\nprogramming](https://www.remotemobprogramming.org/) and their tool\n[mob](https://github.com/remotemobprogramming/mob) written in Go.\n\nI did this rewrite to:\n- remember the order of drivers\n- use any branch as base branch, not only master or main\n- know about the state so we get nice\n    warnings instead of git conflicts and lost refs.\n- and of course... rust ;)\n\nTo find other tools look at the [mob programming timer tag on github](https://github.com/topics/mob-programming-timer)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fafajl%2Fmob","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fafajl%2Fmob","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fafajl%2Fmob/lists"}