Skip to content
open tomato/ rafa
GitHub
rafa pages
  1. rafa
  2. Several devices

Several devices

Bring one project's effort records to a second machine, choose how they travel between devices, and keep two devices off the same issue.

Each project keeps an effort store: a SQLite file under .rafa/effort/ where rafa records every session, task and commit, and what each cost. rafa effort report reads it. When the same project runs on two machines, each keeps its own store until you bring them together, and this page says how.

Pick how the store travels

Set effort.sync in the project's config. The setups, lightest first:

Setupeffort.syncWhy
One laptoplocal (the default)nothing to sync
Two personal devices, now and thenfileno server and no account: you copy a file
Personal projects that sync oftengithistory and access from git, works offline
A company or several teamsserviceone hub, live status, shared rules
Advanced, exploratoryp2pdevices talk directly

Only local and file ship inside rafa. git and p2p are open specs (#326, #327). service needs the hub and its client module, which rafa-hub covers.

effort:
  sync: file

Start a second device

The way that keeps the most history is to copy the first device's store to the second, then merge the two back together later. This is the case the merge handles best: both stores share their early rows, so the shared part collapses to one copy and only what each device added since is new.

  1. On the first device, make a consistent copy of the store. A plain file copy taken while rafa writes can be broken, so use rafa's copy, which writes a folder holding effort.sqlite:

    rafa effort copy --to=<folder>
  2. On the new device, run rafa init in its clone of the project. If .rafa/effort/ already holds a store, rename it or back it up.

  3. Carry the copied effort.sqlite and the project's .rafa/config.yaml over, and put them at .rafa/effort/effort.sqlite and .rafa/config.yaml in the new device's clone. On its first write, the new device's store takes an id of its own, so rows it adds later are told apart from the first device's.

  4. Work on both devices. When you want the records together, make a copy on the new device the same way:

    rafa effort copy --to=<folder>
  5. Carry that effort.sqlite back to the first device and merge it in. --dry-run prints what the import would add and changes nothing:

    rafa effort import <folder>/effort.sqlite --dry-run
    rafa effort import <folder>/effort.sqlite
    Merges <folder>/effort.sqlite (store …) into <project>/.rafa/effort/effort.sqlite, as merge ….
      sessions: 0 added, 0 skipped, 0 in conflict
      commits: 1 added, 1 skipped, 0 in conflict
    …

    Here the commit both devices shared was skipped, and the one the new device made was added. The first device's original store is kept beside it as a .bak file.

WARN

The store holds private text: task descriptions, findings and notes. Move it only between your own devices.

The merge keeps every row from both sides and adds nothing twice, whatever order you merge in and however often. Two stores from different rafa versions are brought to the same schema first; a store from another project, or one a running loop is writing, is refused.

Keep two devices off one issue

Before a device plans or starts an issue, it claims it, so two devices never work the same issue. The claim is a branch pushed to the remote. When two loops read issue #57 as free at once, both push a claim; the first push creates the branch, the second is refused by git, and that loop picks another issue.

A claim on an issue no loop has started yet becomes stale after claims.staleAfter (three days by default), and a stale claim can be taken over; a claim on an issue already in development is never taken over on its own. disabled turns staleness off:

claims:
  staleAfter: disabled
  ahead: allow

claims.ahead: allow lets a run reserve one issue ahead on the roadmap, when you pass --claim-ahead to rafa next --roadmap or rafa plan create --next. rafa claim releases, hands over, accepts or takes over a claim.

A company: one hub

A company or several teams run one hub, and every device syncs through it:

effort:
  sync: service
hub:
  url: https://hub.example.org
  tokenSecret: rafa-hub-token   # the name in the secret store, never the token

With service set and no hub.url in any file, the config is refused when it loads. Setting up the hub, and the module the device needs, is on the rafa-hub pages.

Decisions not taken

Dolt, a database with git-like merges, was considered as the merge engine and set aside: it is a separate server program, and its merge needs a different kind of row id. Random ids (UUIDs) alone were not trusted either: in practice their collisions come from copies, such as a restored backup or a cloned virtual machine, not from chance, so each row's id carries the store it came from. Peer to peer waits until file exchange and the hub, the two strategies a team needs first, are done.