Documentation menu
On this page

Try it in 5 minutes

Time: 5 minutes · Needs: Linux 5.19 or newer (arm64 or x86_64), ssh installed, no root · Result: a command waits in the kernel and runs only after a signed approval

The quickest honest look at the gate. There is no agent and no phone here: wardend supervises a small shell command, and a second terminal plays the phone with a test key. Nothing on this page protects a real agent; for that, use the hardened install.

Not downloadable yet. The install script and the source code open with the first release. The steps below are what you will run then; the outputs are real, from a Raspberry Pi 5.

1. Install for your own user

curl -fsSL https://wardenclaw.dev/install.sh | sh -s -- --single-user

The script checks the release signature, asks for a confirmation and puts wardend into ~/.local/bin, the reference files and uninstall.sh into ~/.local/share/wardend, and an example config into ~/.wardend/config.json. It warns when ~/.local/bin is not in your PATH.

Check: wardend --help prints the usage and exits with code 0.

2. Watch a command in observe

$ wardend run --mode observe --gateway-db off -- sh -c 'ls -d /tmp; git --version'
wardend: mode=observe policy=tripwire pid=767159 child=767168 socket=/home/me/.wardend/wardend.sock journal=/home/me/.wardend/journal.jsonl
/tmp
git version 2.47.3
wardend: mode=observe execs=3 denied=0 latency p50=433us p95=518us max=518us exit=0

Everything runs. wardend counted the execs (execs=3) and wrote to the journal what each would need in ticket mode.

3. Make a command wait for a signature

In the first terminal, create a test device and run a command in ticket mode that trusts it:

(umask 077; wardend keygen > device.txt)     # test device; the seed in it is a secret
DEV=$(sed -n 's/^deviceId=//p' device.txt); PUB=$(sed -n 's/^pubkey=//p' device.txt)
wardend run --mode ticket --gateway-db off --trust "$DEV:$PUB" --ttl 30s --quiet \
  -- sh -c 'ls -d /etc; ssh -V; echo "ssh rc=$?"'

ls prints /etc at once. ssh is remote execution, one of the rules of the default tripwire policy, so it now waits in the kernel, for 30 seconds at most (--ttl).

Within those 30 seconds, in a second terminal in the same directory, sign it with the test key:

$ wardend approve --key "$(sed -n 's/^seed=//p' device.txt)" --count 1 --timeout 10s
allow wd-805763d1887fcfb8a26269e7d38f1db9 argv=[ssh -V] -> map[decision:allow id:wd-805763d1887fcfb8a26269e7d38f1db9 ok:true]

The first terminal prints the OpenSSH version and ssh rc=0. wardend approve is a “device in a terminal”: it reads the waiting request from the socket, recomputes its digest from the envelope as the app does and signs the decision.

4. Deny it

Run the same wardend run command again, and in the second terminal sign a deny:

wardend approve --key "$(sed -n 's/^seed=//p' device.txt)" --deny --count 1 --timeout 10s

The first terminal prints:

/etc
sh: 1: ssh: Operation not permitted
ssh rc=126

The same happens when no answer comes within the TTL: without a signature the command does not run.

5. Check the journal

Every exec and every decision lands in an append-only journal. Each record is hashed into a chain and signed by the supervisor’s key:

wardend verify-journal ~/.wardend/journal.jsonl

On a valid chain it exits with code 0 and warns that the key came from the journal itself. To check authorship too, pass the supervisor’s public key with --pubkey: wardend verify-journal.

6. Clean up

rm device.txt                                        # the test seed
~/.local/share/wardend/uninstall.sh --single-user

Details: Uninstall the trial install.

What you saw, and what you did not

Next

  1. Install wardend on the server for real.
  2. Get the app and connect the phone.