Two daemons on one machine, a file moved by commands alone. About 15 minutes.
We run two independent KeibiDrop daemons on one machine, connect them to each other, and move a file from one to the other with kd commands. Everything we type is scriptable; everything we get back is JSON. This is the whole pattern an automation or an AI agent uses.
kd.exe).jq, for reading JSON in the shell. Any JSON reader works.Each instance needs its own state directory, its own socket, and its own ports. In terminal 1, start Alice:
KEIBIDROP_CONFIG_DIR=/tmp/kd-alice \ KD_SOCKET=/tmp/kd-alice.sock \ KD_INBOUND_PORT=26001 KD_OUTBOUND_PORT=26002 \ KD_SAVE_PATH=/tmp/kd-alice-files KD_NO_FUSE=1 \ kd start
In terminal 2, start Bob with different values:
KEIBIDROP_CONFIG_DIR=/tmp/kd-bob \ KD_SOCKET=/tmp/kd-bob.sock \ KD_INBOUND_PORT=26003 KD_OUTBOUND_PORT=26004 \ KD_SAVE_PATH=/tmp/kd-bob-files KD_NO_FUSE=1 \ kd start
Each daemon prints one JSON line and stays in the foreground. The line contains its socket, fingerprint, and paths. The daemons keep running; our commands go in terminal 3.
A client command finds its daemon through KD_SOCKET. Set up two shell aliases in terminal 3:
alias alice='KD_SOCKET=/tmp/kd-alice.sock kd' alias bob='KD_SOCKET=/tmp/kd-bob.sock kd'
Ask each for its fingerprint:
alice show fingerprint bob show fingerprint
Each prints one line like {"ok":true,"data":{"fingerprint":"..."}}. Notice the shape: every kd response is one JSON object with an ok field.
Each side registers the other's fingerprint, then both connect:
AF=$(alice show fingerprint | jq -r .data.fingerprint) BF=$(bob show fingerprint | jq -r .data.fingerprint) alice register "$BF" bob register "$AF" alice connect & bob connect wait
Both connect calls return when the session is up. Confirm it:
alice status | jq '.data.connection_status, .data.connection_mode'
The output should be "healthy" and a mode, here "lan" since both daemons share one machine.
Create a file, share it as Alice, pull it as Bob:
echo "hello from alice" > /tmp/hello.txt alice add /tmp/hello.txt bob list | jq '.data' bob pull hello.txt /tmp/kd-bob-files/hello.txt cat /tmp/kd-bob-files/hello.txt
The last line prints hello from alice. The file crossed between two encrypted daemons on your machine.
Before scripting further, one rule to learn now. Ask Bob for a file that does not exist:
bob pull no-such-file /tmp/x ; echo "exit=$?"
The response says {"ok":false,"error":"file not found: no-such-file"}, and the exit code is 0. kd's exit code is 1 only when the daemon socket is unreachable. A script must test the ok field:
bob pull no-such-file /tmp/x | jq -e '.ok' || echo "pull failed"
The daemon queues events you can poll:
alice poll-event
Right after connecting, this returns a line like {"ok":true,"data":{"event":"connection_mode:lan"}}. An empty queue returns an empty event string. Polling is non-blocking; an automation loops on it.
alice stop bob stop
Each daemon disconnects, cleans up, and exits. The sockets disappear.
kd start configure it; the socket addresses it.jq makes the shell fluent in it.ok, never the exit code.