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 compares file content by SHA-256, so unchanged files are not re-uploaded.
  • 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.0a0.tar.gz (12.7 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.0a0-py2.py3-none-any.whl (10.0 kB view details)

Uploaded Python 2Python 3

File details

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

File metadata

  • Download URL: keeplock-0.1.0a0.tar.gz
  • Upload date:
  • Size: 12.7 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.0a0.tar.gz
Algorithm Hash digest
SHA256 067043398fd20fd8d1f603a84e3a6f89e775ea123e6c328376dcf1421930fcfd
MD5 59dc9e562983e81f8bccafd53a44055c
BLAKE2b-256 e2430f4dadd3428d77a98184b1896296f614edd1c2b50b951b325f93251ba2fc

See more details on using hashes here.

File details

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

File metadata

  • Download URL: keeplock-0.1.0a0-py2.py3-none-any.whl
  • Upload date:
  • Size: 10.0 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.0a0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 7062683942ee9faa828bdba0bc99b4be2ef8715305ed201b73ef02a6ce14d74c
MD5 ccc935c22892d77ef4d3654a2fec22da
BLAKE2b-256 d4164b134b3cd308082c53bb9c6cd52b89936ee61c5bcd09aca1de0a63feed0b

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0a0 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