# Agentl

`Agentl` is a small "AnyDesk for agents" console relay:

- one relay server on a dedicated TLS TCP port
- one client file that can work as `agent`, `controller`, or one-shot `exec`
- auth by `id/password`
- file copy through the relay with `put/get`
- persistent remote shell sessions with `/session` or `exec --session`
- optional `sudo` wrapping for Unix-like targets
- Linux and Windows support through the same Node.js script

## Human flow

On the managed machine:

```bash
agentl
```

On first run it:

- `ID`
- `Password`
- asks for a password if one is not saved yet
- generates `ID` automatically and registers it on the relay

Then it stays in foreground and keeps the agent online until `Ctrl+C`.

Background mode is still available:

```bash
agentl up
```
Give `ID` and `Password` to the human or another agent.

On the controlling machine:

```bash
./agentl.sh controller
```

Or run a single remote command:

```bash
./agentl.sh exec -- "uname -a"
```

Or copy a file through the relay:

```bash
./agentl.sh put ./local.txt /tmp/remote.txt
./agentl.sh get /tmp/remote.txt ./copy.txt
```

No direct connectivity between the two machines is required. Both sides connect only to the relay.

## Daily commands

Managed side:

```bash
agentl
agentl up
agentl status
agentl credentials
agentl down
```

Controller side:

```bash
./agentl.sh controller
./agentl.sh exec -- "hostname"
./agentl.sh exec --session setup -- "cd /opt && pwd"
./agentl.sh exec --sudo -- "id"
./agentl.sh put ./agentl.conf /tmp/agentl.conf
./agentl.sh get /var/log/syslog ./syslog.txt
./agentl.sh stop-remote
```

Windows wrapper:

```bat
agentl
agentl up
agentl.cmd controller
agentl.cmd exec -- "hostname"
agentl.cmd put .\local.txt C:\Temp\remote.txt
agentl.cmd get C:\Temp\remote.txt .\copy.txt
agentl.cmd stop-remote
```

## Controller REPL

Inside `controller` mode:

- type any shell command to run it remotely
- `/session NAME command` runs inside a persistent remote shell named `NAME`
- `/session-close NAME` closes that persistent shell
- `/put LOCAL REMOTE` uploads a file through the relay
- `/get REMOTE LOCAL` downloads a file through the relay
- `/ping` checks whether the target agent is online
- `/shutdown` stops the remote agent natively
- `/exit` quits the controller

## Relay setup

Start relay:

```bash
node tools/agentdesk/agentdesk.mjs server --host 0.0.0.0 --port 47123 --state-dir /opt/agentl
```

Print relay certificate fingerprint:

```bash
node tools/agentdesk/agentdesk.mjs fingerprint --state-dir /opt/agentl
```

Manual relay override on another server:

```bash
agentl config set-relay --host your-relay.example --fallback-host 203.0.113.10 --port 47123 --fingerprint 'AA:BB:...'
```

## Provisioning model

- `agentl` and `up` create local credentials automatically if they do not exist yet
- missing `id` is generated automatically
- missing password is prompted interactively when a TTY is available
- the relay auto-registers a new agent on first successful agent connection
- after that, controller login with the same `id/password` works immediately
- `credentials` prints the stored local values again later
- built-in defaults point to `suoriks.space:47123` and fall back to `188.214.37.12`

## Shell behavior

- Linux/macOS agent uses `/bin/bash -lc`
- Windows agent uses `powershell.exe -NoLogo -NoProfile -NonInteractive -Command`
- you can override the agent shell with `--shell`
- `exec --session NAME -- "..."` keeps shell state between calls
- `exec --sudo -- "..."` wraps the command with `sudo`

## Security notes

- traffic is TLS-encrypted
- the relay uses a self-signed certificate by default
- the TLS fingerprint is the relay certificate identity; pinning it prevents talking to the wrong relay or a MITM
- the current built-in relay is `suoriks.space:47123`
- if DNS access fails, the client can retry the built-in fallback host `188.214.37.12`
- if the relay certificate is rotated, run `config set-relay --fingerprint ...` once
- passwords are stored on the relay with `scrypt`
- this is still an admin tool, so use strong passwords and keep the relay port private if possible
