aly.codes/appa

· Tangled

3 min read Original article ↗

Appa keeps folders in sync directly between your devices. It has no account and no central file server. Each device runs one local daemon; the command line and COSMIC app talk to that daemon.

Start the daemon#

Install the per-user service once:

appa service install

It starts now and at login. Use appa service status, restart, logs, or uninstall to manage it.

For development or another process manager, run it in the foreground:

appa daemon serve

On the first device:

appa folder add ~/notes
appa folder invite ~/notes

On another device, create the destination directory and join with the invitation:

appa folder join ~/notes --stdin

An invitation grants access to one folder. Treat it like a password.

Check a folder at any time:

appa folder status ~/notes
appa folder peers ~/notes
appa folder members ~/notes

appa folder status --watch refreshes the display once a second.

Everyday commands#

Task Command
Add a local folder appa folder add <folder>
Invite a device appa folder invite <folder>
Join a shared folder appa folder join <folder> --stdin
View health appa folder status [folder]
View conflicts appa folder conflicts <folder>
View saved revisions appa folder history <folder>
Restore a revision appa folder restore <folder> <revision>
Verify the audit log appa folder audit <folder> --verify
Remove local Appa state appa folder remove <folder>

remove leaves files alone. It does not revoke the device from the shared folder. Only the folder owner can revoke a member:

appa folder revoke ~/notes <device-id>

Revocation rotates the folder capability. Create new invitations for members who should retain access.

Local folder inventory#

Appa can export and import a small, non-secret list of local folders. It is for setting up local paths and sync modes in bulk, not for sharing folders.

appa folder template
appa folder validate
appa folder import

The default file is appa.toml. Entries contain a path, optional display name, and local mode. They do not contain invitations, capabilities, identities, or membership. folder import is additive: it registers missing folders and updates local modes, but never removes a folder absent from the file.

Files and conflicts#

Add .appaignore at a folder root to keep matching paths local. It uses gitignore syntax. Symlinks are ignored and non-Unicode filenames are rejected.

When devices edit the same file while disconnected, Appa keeps both versions. Use appa folder conflicts <folder> to find the additional copies, then choose the content you want.

Appa keeps 10 local revisions by default. Set APPA_HISTORY_REVISIONS to a positive value to change that limit.

Older Appa releases may have left persistent blob tags behind. Use appa doctor --drop-legacy-tags to remove them; periodic garbage collection will later reclaim blobs that are no longer referenced by Appa state.

Identity and diagnostics#

Each installation has a device identity. Back it up outside synchronized folders:

appa identity
appa identity export ~/appa-identity-backup

The backup can act as the device. Keep it private. Stop the daemon before importing it on a replacement device:

appa identity import ~/appa-identity-backup

For problems, start with:

appa doctor

Set RUST_LOG=appa=debug for detailed logs. APPA_HOME changes the location of Appa's local state.

Build#

Appa requires Rust 1.97.1 or newer.

cargo install --path .

With Nix:

nix develop -c cargo build
nix build .#

The optional COSMIC companion is built with:

nix develop -c cargo run -p appa-cosmic

License#

MIT.