Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Keeplock

Deliberate hand-offs for developers who work across devices.

Keeplock lets you publish a scratchpad from one terminal and mirror it onto others, without Git or a background sync service. Each namespace on the central server has one owning Keeplock identity key. From another device, you can clone or pull that namespace as a read-only mirror.

Keeplock has no server component. The server only needs to accept SSH connections, and all Keeplock state lives under .keeplock in the remote SSH user's home directory.

Installation

pip install keeplock

Keeplock requires the SSH server to provide an SFTP subsystem (the default on OpenSSH). It uses paramiko for the SSH connection and SFTP transfer.

How it works

A namespace is a directory stored on the server. Its name is also the name of its local directory. Each namespace is bound to exactly one owning Keeplock identity key, identified by the fingerprint:

sha256-<lowercase-hex-sha256-of-the-identity-public-key-blob>

Server storage:

.keeplock/
  sha256-<identity-fingerprint>/
    <namespace>/

The Keeplock identity key is independent of the SSH credential used to access the server.

Usage

Every command supplies exactly one SSH server-access option:

--ed25519-key <path> | --rsa-key <path> | --password <password>

--ed25519-key and --rsa-key take a path to the private key used to access the SSH server. --password takes the SSH server password as its value.

A command may also supply at most one Keeplock identity option:

--identity-ed25519-key <path> | --identity-rsa-key <path>

--identity-ed25519-key and --identity-rsa-key take a path to the Keeplock identity key that determines namespace ownership. When neither is given, Keeplock looks for ~/.ssh/id_ed25519 and then ~/.ssh/id_rsa.

In the command synopses below, (...) marks a required choice (pick exactly one) and [...] marks an optional argument.

Create a namespace

keeplock init <name> --host <host> [--port <port>] --username <username> \
    (--ed25519-key <path> | --rsa-key <path> | --password <password>) \
    [--identity-ed25519-key <path> | --identity-rsa-key <path>]

<name>, --host, and --username are required; --port is optional (default 22). Exactly one of the server-access options is required, and the identity option is optional.

For example:

keeplock init phone --host server.example.com --username user --ed25519-key ~/.ssh/server_access_ed25519

This creates the remote namespace, binds it to the Keeplock identity key, and creates ./phone containing only .keeplock.json:

{
  "host": "server.example.com",
  "port": 22,
  "username": "user"
}

.keeplock.json holds only the server connection details; it never stores server-access credentials or Keeplock identity keys.

List namespaces

keeplock ls --host <host> [--port <port>] --username <username> \
    (--ed25519-key <path> | --rsa-key <path> | --password <password>) \
    [--identity-ed25519-key <path> | --identity-rsa-key <path>]

--host and --username are required; --port is optional (default 22). Exactly one of the server-access options is required, and the identity option is optional.

For example:

keeplock ls --host server.example.com --username user --ed25519-key ~/.ssh/server_access_ed25519
write:      phone
read-only:  laptop
read-only:  termux

Publish the current tree

Run inside a namespace directory:

keeplock push [-d | --dry-run] \
    (--ed25519-key <path> | --rsa-key <path> | --password <password>) \
    [--identity-ed25519-key <path> | --identity-rsa-key <path>]

Exactly one of the server-access options is required. -d/--dry-run and the identity option are optional. --host, --port, and --username are read from .keeplock.json.

For example:

keeplock push --ed25519-key ~/.ssh/server_access_ed25519
Verifying this Keeplock identity key owns "phone"... ok
Mirroring server tree to match local... done
remote: tree updated

Use -d/--dry-run to report the changes without making them.

Clone a mirror

keeplock clone <name> --host <host> [--port <port>] --username <username> \
    (--ed25519-key <path> | --rsa-key <path> | --password <password>) \
    [--identity-ed25519-key <path> | --identity-rsa-key <path>]

<name>, --host, and --username are required; --port is optional (default 22). Exactly one of the server-access options is required, and the identity option is optional.

For example:

keeplock clone phone --host server.example.com --username user --ed25519-key ~/.ssh/server_access_ed25519

If the current Keeplock identity key does not own the namespace, the clone is a read-only mirror.

Pull the current tree

Run inside a namespace directory:

keeplock pull [-d | --dry-run] \
    (--ed25519-key <path> | --rsa-key <path> | --password <password>) \
    [--identity-ed25519-key <path> | --identity-rsa-key <path>]

Exactly one of the server-access options is required. -d/--dry-run and the identity option are optional. --host, --port, and --username are read from .keeplock.json.

For example:

keeplock pull --ed25519-key ~/.ssh/server_access_ed25519

pull updates the local mirror to match the server tree. Local files not present on the server are removed. Use -d/--dry-run to report the changes without making them.

Notes

  • push and pull read the server connection details from .keeplock.json and the namespace name from the current directory name.
  • push and pull compare each file's size and modification time, so unchanged files are not re-transferred. Transfers preserve modification times to keep later syncs fast.
  • Keeplock mirrors regular files and directories. Symbolic links and other special files are ignored.
  • A namespace found under multiple identity directories is an error; manual server cleanup is required.

Running the tests

From the project root:

python -m unittest discover -s tests -t .

The tests exercise the namespace scanner, the push/pull tree synchronization engine, configuration round-trips, change records, and argument parsing.

Contributing

Contributions are welcome! Please submit pull requests or open issues on the GitHub repository.

License

This project is licensed under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

keeplock-0.1.0a1.tar.gz (13.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

keeplock-0.1.0a1-py2.py3-none-any.whl (10.5 kB view details)

Uploaded Python 2Python 3

File details

Details for the file keeplock-0.1.0a1.tar.gz.

File metadata

  • Download URL: keeplock-0.1.0a1.tar.gz
  • Upload date:
  • Size: 13.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for keeplock-0.1.0a1.tar.gz
Algorithm Hash digest
SHA256 1b51525e3fd38e77a38b0a6a4073d00778aa3e8759f7296f1efb24e06d14f357
MD5 0ddfacc21ef5176d2eca7e672d4f9c6e
BLAKE2b-256 3fa807b5ca73c8245d268237c3338287ab1979e2716b9f42df77178d7b2c72a7

See more details on using hashes here.

File details

Details for the file keeplock-0.1.0a1-py2.py3-none-any.whl.

File metadata

  • Download URL: keeplock-0.1.0a1-py2.py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.6

File hashes

Hashes for keeplock-0.1.0a1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 183bcbb76812b0535d6caf0167a98b0902c5ac034a2eaf1cf40f49f65f7120eb
MD5 f916c42b7a6e822cd87d8b766a74cf1e
BLAKE2b-256 cd397adc31234caca18af0a865229cd77677eaafa57193ac88a0d0014c24fb01

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0a1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page