A pair programming service using operational transforms



godoc for jeffail/leaps goreportcard for jeffail/leaps

Leaps is a service for collaboratively editing your local files over a web UI, using operational transforms to ensure zero-collision synchronization across any number of editing clients.

WARNING: This project is no longer actively maintained.



Simply navigate to a directory you want to share, run leaps, open the hosted page (default http://localhost:8080) in your browser and direct any friends on your LAN to the same page. You can now collaboratively edit any documents in that directory.

Your files will be written to in the background as you edit. If you aren't using version control, or simply want extra protection, you can run leaps in safe mode with the --safe flag. In safe mode any changes you make will be placed in a .leaps_cot.json file, which you can then apply to your files once you are happy by running with the --commit flag.

Build/test commands from the UI

When writing code it sucks to have to leave the editor for running tests, linters or builds. However, allowing the internet to run arbitrary commands on the host machine is a recipe for disaster.

Instead, leaps allows you to specify pre-written commands using the -cmd flag, which are then available for clients to trigger asynchronously while they edit. Results are broadcast to all connected users, so you can all see the outcome as a team.

For example, leaps -cmd "golint ./..." -cmd "go build ./cmd/leaps" gives users both a linter and a build command that they can trigger on your machine.


Leaps can also be used as a library, with implementations of accessors for various document hosting solutions and plugable authentication layers, allowing you to build your own services to suit many service architectures.

Leaps server components are implemented in Golang, and has a client implemented in JavaScript that can currently be used with ACE, CodeMirror and Textarea editors.

To read more about the service library components and find examples check out the godocs.

To read about the JavaScript client check out the README.


Leaps is a single binary, with no runtime dependencies. Just download a package for your OS from the latest releases page.

From homebrew

brew install leaps
leaps -h

Build with Go

go get github.com/Jeffail/leaps/cmd/...
leaps -h

System compatibility

OS Status
OSX x86_64 Supported, tested
Linux x86 Supported
Linux x86_64 Supported, tested
Linux ARMv5 Builds
Linux ARMv7 Supported, tested
Windows x86 Builds
Windows x86_64 Builds

Contributing and customizing

Contributions are very welcome, just fork and submit a pull request.


Ashley Jeffs

  • 404 for every request?

    404 for every request?

    Hey mate, I use your Gabs library and just found this other project. Very cool!

    However, it doesn't work for me. I've done:

    go get github.com/jeffail/leaps

    When I run leaps from within a folder I get:

    Launching a leaps instance, use CTRL+C to close.
    2016-04-15T16:36:21+01:00 | INFO | service:http | Listening for websockets at address: localhost:8080/leaps/socket
    2016-04-15T16:36:21+01:00 | INFO | service:http | Serving static file requests at address: localhost:8080/leaps
    2016-04-15T16:36:21+01:00 | INFO | service:http_admin | Serving internal admin requests at address: localhost:4040/admin

    But any request to localhost:8080 or localhost:4040 or localhost:4040/admin result in "404 page not found". If I shutdown leaps then I get connection refused (so it's definitely hitting the daemon).

    Any ideas?

    opened by andyjeffries 12
  • Homebrew formula started

    Homebrew formula started

    The problem I'm having is in the final build command. It's doing something like this:

    go build -o /usr/local/Cellar/leaps/0.5.0/bin/leaps cmd/leaps/leaps.go
    # command-line-arguments
    # cmd/leaps/leaps.go:164: undefined: assetFS

    I can't build it with go build -o /usr/local/Cellar/leaps/0.5.0/bin/leaps cmd/... because it doesn't like the -o flag when giving multiple packages.

    Any tips on how I can do a one liner build for leaps that just outputs me a single binary in a configurable place?

    If you want to see, the issue on Homebrew is at https://github.com/Homebrew/homebrew-core/issues/610 and the current version of the formula is at https://github.com/andyjeffries/homebrew-core/blob/master/Formula/leaps.rb

    opened by andyjeffries 10
  • reverse proxy support

    reverse proxy support

    reverse proxy setup

    i tried to run leaps behind a reverse proxy, say:

    https://example.com/leaps -> localhost:8080/leaps


    https://example.com/leaps -> localhost:8080/
    (this would require a different apache proxy configuration as shown below)

    but i did not find a way to make leaps know it runs in a subdirectory. is there a configuration option?

    apache config

    # prevent a forward proxy! 
    ProxyRequests off
    # User-Agent / browser identification is used from the original client
    ProxyVia Off
    ProxyPreserveHost On
    RewriteEngine On
    RewriteRule ^/leaps$ /leaps/ [R]
    <Proxy *>
    Order deny,allow
    Allow from all
    ProxyPass /leaps/ retry=0
    ProxyPassReverse /leaps/


    does anyone here have a working reverse proxy setup for apache or any other WS?

    enhancement help wanted 
    opened by qknight 9
  • binderMutex shouldn't have I/O in critical sections

    binderMutex shouldn't have I/O in critical sections

    We critically should fix the binderMutex lock... The critical section covers NewBinder which does a store.Fetch... This is problematic as people can't join/create documents while we wait for a single document to be loaded...

    I looked at it, and I think we should just make an Abort method on binder that aborts the loop without saving anything... I just couldn't quiet figure out how to do it... @Jeffail, If you can give a hint on how to make an Abort() function that doesn't save the bind, but cleans up all resources, I can do the rest :) (I'm still a bit new to golang)

    With the abort function we can do as follows:

    1. Lock binderMutex
    2. Look in openBinders for binder
    3. Unlock binderMutex
    4. Create binder: b := NewBinder(...)
    5. Lock binderMutex
    6. If binder := openBinders[id] exists, call b.Abort(), else set binder := openBinders[id] = b
    7. Unlock binderMutex
    8. return binder.Subscribe(...

    Sure, sometime we may create a binder without any clients at the same time as another client creates the same binder... But the binder that is added to openBinders[id] is the one both will use, and the other binding will be aborted before any clients are subscribed to it...

    opened by jonasfj 9
  • Fresh go get -u failure

    Fresh go get -u failure

    Have had this failure for a long time now.

    % go get github.com/jeffail/leaps/cmd/...
    % go get github.com/jeffail/leaps/cmd/...
    % go get -u github.com/jeffail/leaps/cmd/...
    package github.com/jeffail/leaps/vendor/github.com/elazarl/go-bindata-assetfs: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/elazarl/go-bindata-assetfs/.git exists but is not a directory
    package github.com/jeffail/leaps/vendor/github.com/garyburd/redigo/redis: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/garyburd/redigo/.git exists but is not a directory
    package github.com/jeffail/leaps/vendor/github.com/jeffail/util/log: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/jeffail/util/.git exists but is not a directory
    package github.com/jeffail/leaps/vendor/github.com/go-sql-driver/mysql: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/go-sql-driver/mysql/.git exists but is not a directory
    package github.com/jeffail/leaps/vendor/github.com/satori/go.uuid: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/satori/go.uuid/.git exists but is not a directory
    package github.com/jeffail/leaps/vendor/github.com/lib/pq: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/lib/pq/.git exists but is not a directory
    package github.com/jeffail/leaps/vendor/github.com/amir/raidman: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/amir/raidman/.git exists but is not a directory
    package github.com/jeffail/leaps/vendor/github.com/jeffail/gabs: /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/jeffail/gabs/.git exists but is not a directory
    % ls -al /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/elazarl/go-bindata-assetfs/.git 
    -rw-r--r--  1 fail  staff  -   78B Apr  9 17:37 /Users/fail/work/go/src/github.com/jeffail/leaps/vendor/github.com/elazarl/go-bindata-assetfs/.git
    opened by junkblocker 7
  • Local editor has lost synchronization with server

    Local editor has lost synchronization with server

    problem description

    we use leaps (0.6.0) with codemirror (with an old version but also with 5.26). it used to work months ago and then we found that opening the same document in two tabs (one in firefox, the other in chromium) leads to this error message in the javascript error console of tab A:

    Local editor has lost synchronization with server

    when one enters any letter in tab B (or vice versa) but, and this puzzles me, when both tabs are reloaded i can use del key to remove a letter or space and it keeps the sync.

    seeking advice

    now i don't know exactly where to search for a solution, any hints what could cause this would be great.

    what i've done so far:

    • in the go code i've added: + logConf.LogLevel = "ALL" and it prints lots of interesting lines, but no obvious error message
    • in the frontend code i've also added lots of debugging lines and checked the network messages in the /leaps/ws websocket but nothing obvious either

    possible causes

    • we traverse the /leaps/ws trough a nginx reverse-proxy, maybe this caused it (i will try to remove this but haven't done yet)
    • we started to update to from leaps 0.6.0 to leaps 0.8.4 but that turns out to be more effort since you are using gorilla websockets and we use the websockets coming with golang.org/x/net
    • we could try to replace codemirror with ace (seems to be much work though)
    opened by qknight 6
  • save button

    save button

    Hi, thank you for your work, Jeffail.

    It would be better if we have save button.

    It feels little bit unsafe, because every changes are applied to file directly.

    enhancement help wanted 
    opened by kybin 5
  • Connect to document closed READ ONLY

    Connect to document closed READ ONLY

    So, now I've got it running properly, I'm trying to test collaboration. The following are my steps:

    1. Run leaps from within my project's folder
    2. Open localhost:8001 on my local machine
    3. Open on my iPad
    4. Set my name as "andyjeffries" on my local machine's browser
    5. Set my name as "andy iPad" on my iPad
    6. In my local machine's browser, I click on a file "forgot_password_action.rb" in this case
    7. My local machine opens it for editing
    8. I tell the other developer (myself) by some means (maybe chat, maybe verbally) to open the same file
    9. I click the same file on my iPad.
    10. The iPad chat bar now says "Connection to document closed, document is now READ ONLY" in a red block.
    11. The local machine's browser's chat bar says the same thing
    12. Neither browser can now edit that file

    So I don't know how I could collaboratively edit a file with another developer?

    In Step 8 it would be great if the system listed all current users, what file they are looking at, with an icon to jump to the same file (and line their cursor is on).

    opened by andyjeffries 5
  • Poor fella dies during build

    Poor fella dies during build

    lib/store/azure_blob_store.go:99: not enough arguments in call to m.blobStorage.CreateBlockBlobFromReader

    I'll use the released binary for nwo..... thanks for an awesome app!

    opened by faddat 5
  • Initial work on making userId and token unconfused

    Initial work on making userId and token unconfused

    Just getting started on this... Feel free to jump in too...

    I've made all members of BinderClient lower case so they won't be exported (If I recall go correctly)..

    Then use *BinderClient pointer instead of token as the identifier... I suspect we should get completely rid of BinderClient and instead just use BinderPortal.

    I think this is almost mergeable now, feel free to give it a quick... I haven't really tested it... Next step is to ensure that we always have a userId... I think right now it's just an empty string because I don't set it...

    @Jeffail, I suggest we drop the KickUser(userId string, timeout time.Duration) functionality, I don't see the use-case when the kicked user can immediately reconnect. Something like this is better solved at auth level, and kicking a user that is currently watching seems like something very complicated.

    It seems more realistic that an auth provider implements a way to purge a token, and the next time the client reconnects the client won't be granted access. But kicking active clients as well, seems too hard (with too little usecase). If we really wanted it, it would probably be better than auth had a method it could call forcing all binders to re-evaluate all tokens, and then kick users.

    IMO this is however not a good feature at this point. Agree?

    opened by jonasfj 5
  • golang/dep



    please check: https://github.com/nixcloud/leaps-go-dep

    using nix/nixos it is quite hard to package leaps and other go based softwares unless they use the new https://github.com/golang/dep utility. that is because we have https://github.com/nixcloud/dep2nix now and this makes some things easier.

    that said, it best works if the upstream project also uses dep and with this repository i've played with dep deployment for leaps. so the question is: how do you like the idea of not using git submodules and using dep instead for dependency management? we at nixcloud are in the process of migrating our projects to dep.

    if there is interest i would use the latest leaps master and create a PR. i'd like that!


    the lib directory has a special role, as it is referenced by: import with github.com/Jeffail/leaps/lib and it still does not have to be a 'single' package with an upstream git repository.

    see also https://github.com/nixcloud/leaps-go-dep/blob/master/src/github.com/jeffail/leaps/leaps.go#L38

    opened by qknight 4
  • inlets for over not just LAN

    inlets for over not just LAN


    This does not have to be added to htis lib, but just more letting people know how easy it is to expose your local running gaps over a HTTPS domain.

    You can run inlets on CloudRun or ko ( https://github.com/google/ko)

    opened by winwisely99 0
  • undefined: assetFS

    undefined: assetFS

    I am new to golang. Trying to use this package but got this error when I run leaps.go: github.com/Jeffail/leaps/cmd/leaps/leaps.go:343:68: undefined: assetFS

    I searched around but couldn't find a solution.

    opened by visortown 2
  • unit test

    unit test

    i want to use javascript with selenium to test if leaps is working correctly but i don't know how to insert 'text' into the textedit.

    are you doing that already? any idea welcome!

    opened by qknight 3
  • Feature: Split Markdown view in editor.

    Feature: Split Markdown view in editor.


    Leaps looks awesome. Have you given thought to having a markdown preview option something similar in the editor to the following:

    |      |                |          |
    | File | Input          | Comments |
    | List |                |          |
    |      |                |          |
    |      +----------------+          |
    |      |                |          |
    |      |                |          |
    |      | Preview        |          |
    |      |                |          |

    I suppose it could be more generalised to being a command output pane but markdown preview would be nice as a first kick of the tires. :)

    Kind Regards, Nathan

    enhancement help wanted 
    opened by nfisher 2
  • Hiding uneditable files

    Hiding uneditable files

    Maybe there could be a .leapsignore folder in a project's folder specifying files to not be shown (just like .gitignore). Then we could put:


    In there (for a start) to stop it from showing the source of images.

    As an additional option, if leaps could detect that it's a binary file and not likely to be UTF-8 editable text, and pop up a warning, that would be awesome too! https://golang.org/pkg/unicode/utf8/#ValidString

    opened by andyjeffries 3
  • Feature request(s) - config, display public IP, and open

    Feature request(s) - config, display public IP, and open

    It would be really nice if there was a ~/.leapsrc or something (maybe TOML or JSON, something easy to parse in Go) you could define options in.

    Then if you had a config file you could put options like the following:


    So when you run leaps, it would automatically look within ifconfig's output for an IP address matching local_ip (because on a DHCP LAN this often changes), and then can automatically open (by shelling out to the OS X open command) a browser to the correct URL (ready to copy and paste and share to someone).

    Just used it with one of our more junior developers, and getting them from running leaps to sharing the URL with me still had the above hurdles - the suggestion above would remove them.

    opened by andyjeffries 0
Ashley Jeffs
If you want to get in touch please find me in person I'm not good with computers.
Ashley Jeffs
go library for image programming (merge, crop, resize, watermark, animate, ease, transit)

Result Terminal Code mergi -t TT -i https://raw.githubusercontent.com/ashleymcnamara/gophers/master/Facepalm_Gopher.png -r "131 131" -i https://raw.gi

Noel Yahan 181 Aug 29, 2022
The android-go project provides a platform for writing native Android apps in Go programming language.

android-go The android-go project aims to provide a platform (namely an SDK) for writing native Android apps in Go programming language. All things he

Max Kupriianov 972 Aug 16, 2022
Image resizing for the Go programming language with common interpolation methods

This package is no longer being updated! Please look for alternatives if that bothers you. Resize Image resizing for the Go programming language with

null 1 Dec 14, 2021
📸 Clean your image folder using perceptual hashing and BK-trees using Go!

Image Cleaner ?? ?? ➡ ?? This tool can take your image gallery and create a new folder with image-alike-cluster folders. It uses a perceptual image ha

lord_santanna 7 Jun 15, 2022
Favicon service written in Go

favicon-service (besticon) This is a favicon service: Supports favicon.ico and apple-touch-icon.png Simple URL API Fallback icon generation Docker ima

Matthias Lüdtke 604 Sep 13, 2022
Go package for computer vision using OpenCV 4 and beyond.

GoCV The GoCV package provides Go language bindings for the OpenCV 4 computer vision library. The GoCV package supports the latest releases of Go and

The Hybrid Group 5k Sep 19, 2022
go-pix is a Go library for generating Pix transactions using Copy and Paste or QR codes. 💳 💰

go-pix go-pix is a Go library for generating Pix transactions using Copy and Paste or QR codes.

Jonnas Fonini 63 Sep 12, 2022
User programmable screen overlay using web technologies

Topframe User programmable screen overlay using web technologies Display information and always-on-top widgets Use HTML/JS/CSS to draw on your screen

Jeff Lindsay 321 Sep 10, 2022
Canvas is a Go drawing library based on OpenGL or using software rendering that is very similar to the HTML5 canvas API

Go canvas Canvas is a pure Go library that provides drawing functionality as similar as possible to the HTML5 canvas API. It has nothing to do with HT

Thomas Friedel 433 Sep 21, 2022
🔍 gowitness - a golang, web screenshot utility using Chrome Headless

?? gowitness A golang, web screenshot utility using Chrome Headless. introduction gowitness is a website screenshot utility written in Golang, that us

SensePost 1.8k Sep 25, 2022
Convert images to computer generated art using delaunay triangulation.

▲ Triangle is a tool for generating triangulated image using delaunay triangulation. It takes a source image and converts it to an abstract image comp

Endre Simo 2k Sep 19, 2022
Create a cool glass-like pattern using Voronoi cells

voronoi-glass Have you ever looked through a shower door made of intentionally uneven glass? Everything looks distorted, but maybe also beautiful. Now

Alex Nichol 8 Jul 21, 2022
Simple image compression using SVD

SVD image compression An implementation image compression using SVD decomposition on Go Built With Go 1.17 Gonum Compression examples Header Image Ori

null 4 Mar 30, 2022
A Pong clone made from scratch with Go and C using OpenGL 3.3

Go-Pong A Pong video game clone made with Go lang and OpenGL 3.3 using C. Gameplay Offline Key bindings are 'w' and 's' for the left player and 'up ar

Mohammad Issawi 33 Feb 10, 2022
Cryptseaside generates seaside images using Unix nanoseconds as the seed value.

Cryptseaside Welcome to the Cryptseaside project. Cryptseaside generates seaside images using Unix nanoseconds as the seed value.

Rhymof 1 Nov 12, 2021
Radius parsing in golang using gopacket. You can parse from either live traffic or from pcap of your choice.

go-radius Radius parsing in golang using gopacket. You can parse from either live traffic or from pcap of your choice. RADIUS RADIUS is an AAA (authen

Adeel Khan 4 Dec 27, 2021
A festive Christmas tree GIF generator implemented using only Golang standard library code

Christmas Tree GIF Generator A festive Christmas tree GIF generator implemented

Golang Dorset 0 Feb 4, 2022
Human-friendly Go module that builds and prints directory trees using ASCII art

Human-friendly Go module that builds and prints directory trees using ASCII art.

Vadym Borodin 4 May 23, 2022
Very simple SVG to PNG converter library using the Inkscape.

svg2png Description Very simple SVG to PNG converter library using the Inkscape.

null 0 Jan 11, 2022