PyKeePassGate
The reference client for KeePassGate, a KeePass 2.x plugin that serves a small specification-defined API over mutual TLS so that automation and AI agents can each be given a narrow, revocable, audited slice of a database.
Reference implementation means the code here is the second copy of the specification. Where the plugin and this disagree, one of them is wrong and a test should already have said so. It also means what is missing is a statement: a route with no method here is a route the gate does not serve.
Install
uv add pykeepassgate
One dependency, cryptography, because the gate hands over a PKCS#12 and Python's ssl reads PEM.
Everything else, the command line included, is the standard library.
Pair
The operator presses Renew invite on the KPG tab of the database's settings dialog and sends
the invitation over a second channel. What they see while doing it is
docs/pairing.md, and worked examples of everything below are
docs/pykeepassgate.md. It is spent by the first client to use it
and it does not survive KeePass closing.
pykeepassgate pair --port 45678 --name agent-invented --profile-name reader
Leave --invitation off and the token is read from standard input, so it stays out of the shell
history and out of the process list.
The same thing from a program:
from pykeepassgate import api
credentials = api.pair(
port=45678,
invitation="...",
name="agent-invented",
profiles=["reader"],
)
print(credentials.profiles) # what the operator approved, not what was asked for
Use
from pykeepassgate import GateClient
client = GateClient.open()
print(client.status())
pykeepassgate status
pykeepassgate whoami
What to catch
Every exception says what to do next rather than what went wrong, because that is the part a caller has to decide.
| Exception | What it means, and what to do |
|---|---|
DatabaseLocked |
The database is locked. Wait, and try again. |
GateBusy |
The gate cannot write right now, usually because a group dialog is open. Retry. |
NotAdmitted |
This database holds no record for this certificate. It was never admitted, or it was revoked. Pair again. |
ProofRefused |
During pairing: the token is wrong, or whatever answered is not the KeePass whose operator holds it. Stop. |
PairingRefused |
The operator said no. The invitation is spent, so ask for another. |
PairingUnanswered |
Nobody answered the dialog. The invitation is not spent, so this can be tried again. |
RouteRefused |
Everything else the gate refuses, carrying the status and the one word it used. A 404 is deliberately both "no such node" and "not yours", so a client cannot map a database by asking: if the node should be there, the rule is too narrow and the operator has to widen it. |
MalformedToken |
The text handed over is not an invitation, so nothing was sent. Check what was pasted. |
ProtocolError |
Something on the wire is not what the protocol allows: an answer this client cannot read, or a request it will not send. Do not retry an answer it cannot read: the two halves disagree about the wire, which tests/pykeepassgate/test_protocol.py exists to stop. |
StorageError |
What is stored for this client will not read, or could not be written. Look at the directory status names. |
TransportError |
Nothing is listening, or the handshake failed. |
What it does not do
It does not open a .kdbx. There is no file and no master password on this side of the API, by
design. What that means for anybody expecting a pykeepass object is measured on the
spikes/pykeepass-compatibility branch: 23 of its 56 public members are servable over the routes the
gate already has, and the object itself is not one of them.
It defends nothing against local code execution as the user. The client's key is on the disk, because a client has to still be the same client tomorrow. The whole design concedes this throughout, and so does this.
Release files for pykeepassgate 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pykeepassgate-0.0.1.tar.gz | 34.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pykeepassgate-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 77.8 kB
Release files / pykeepassgate-0.0.1.tar.gz
| Download URL | pykeepassgate-0.0.1.tar.gz |
|---|---|
| Size | 34.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
97158a8e5b04f0734daaaba0351e2b0152236b6599ec415c847e54b64719bbb0
|
|
BLAKE2b-256 checksum How to use checksums |
03df22008579aa86d178490036c95bdeeda0e2398bb5e22abb36f42aa820e3e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / pykeepassgate-0.0.1-py3-none-any.whl
| Download URL | pykeepassgate-0.0.1-py3-none-any.whl |
|---|---|
| Size | 43.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2e8b6b25be7a5ccefcf526acc7b86413c8e0e76f499f595a3a64cada398ce829
|
|
BLAKE2b-256 checksum How to use checksums |
d584809bfec1e5c44e8f7d73675cd4ef28df729efedbbc5fac285c6790126b19
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|