rafa pages
- rafa
- 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:
| Setup | effort.sync | Why |
|---|---|---|
| One laptop | local (the default) | nothing to sync |
| Two personal devices, now and then | file | no server and no account: you copy a file |
| Personal projects that sync often | git | history and access from git, works offline |
| A company or several teams | service | one hub, live status, shared rules |
| Advanced, exploratory | p2p | devices 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.
-
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> -
On the new device, run
rafa initin its clone of the project. If.rafa/effort/already holds a store, rename it or back it up. -
Carry the copied
effort.sqliteand the project's.rafa/config.yamlover, and put them at.rafa/effort/effort.sqliteand.rafa/config.yamlin 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. -
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> -
Carry that
effort.sqliteback to the first device and merge it in.--dry-runprints what the import would add and changes nothing:rafa effort import <folder>/effort.sqlite --dry-run rafa effort import <folder>/effort.sqliteMerges <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
.bakfile.
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.