-
Notifications
You must be signed in to change notification settings - Fork 4
CLI Machines Power
ed machines power is the run state of another machine: whether it is up, and
the three things you can tell it to do about that, which are restart, shut down
and wake. This page also covers the neighbouring verbs that act on what is
running there rather than on the machine itself: ed machines services for
systemd units, ed machines kill for a single process, and
ed machines broadcast for one line on every machine at once.
Everything here is the Tools tab of a machine window as a command, plus the
terminal's broadcast bar. Nothing here needs the Edith app to be running:
status reads the machine file on disk, wake opens a UDP socket, and the rest
go out over /usr/bin/ssh on the ControlMaster socket Edith and ed share.
Most of this page is disruptive. Read the next table before you type anything.
| Command | Disruptive? |
|---|---|
ed machines power status |
No. Reads the machine file and pokes the local control socket. Never contacts the machine. |
ed machines power reboot |
Yes, and it takes the machine down. Refuses to act without --yes. |
ed machines power shutdown |
Yes, and the machine will not come back without wake or a physical power button. Refuses to act without --yes. |
ed machines power wake |
Mildly. It puts one broadcast packet on the local network and nothing else. |
ed machines services ls |
No. Reads systemctl list-units. |
ed machines services start |
Yes, it changes a unit's state. No confirmation flag. |
ed machines services stop |
Yes, it changes a unit's state. No confirmation flag. |
ed machines services restart |
Yes, it changes a unit's state. No confirmation flag. |
ed machines kill |
Yes, it signals a live process. No confirmation flag. |
ed machines broadcast |
As disruptive as the line you give it, multiplied by every machine you own. No confirmation flag. |
Only reboot and shutdown have a --yes gate. services stop, kill and
broadcast act the moment you press return.
| Command | What it does |
|---|---|
ed machines power status |
Reports whether a shared connection is open, the stored MAC address, and which power verbs are possible right now. Runs when you type ed machines power <machine> with no verb. |
ed machines power reboot |
Restarts the machine through systemd. Does nothing without --yes. Aliased as restart. |
ed machines power shutdown |
Powers the machine off through systemd. Does nothing without --yes. Aliased as poweroff. |
ed machines power wake |
Sends a wake-on-LAN magic packet to the machine's stored MAC address. The one verb that works while the machine is off. |
ed machines services ls |
Lists systemd service units, with --failed to narrow to broken ones. Runs when you type ed machines services <machine> with no verb. |
ed machines services start |
Starts one unit. |
ed machines services stop |
Stops one unit. |
ed machines services restart |
Restarts one unit. |
ed machines kill |
Sends a signal to one process id, TERM unless you name another. |
ed machines broadcast |
Runs one command on every configured machine, labels each machine's output, and exits 1 if any of them failed. |
Every command on this page except broadcast takes the machine as a positional
argument, and the machine can come first instead. The first line of each pair
below puts the verb first and the machine last, the second puts the machine
first.
ed machines power reboot tuf --yes
ed machines tuf power reboot --yes
ed machines services restart tuf nginx.service
ed machines tuf services restart nginx.service
Both forms parse to the same thing. What does not work is the bare shorthand:
ed tuf power reboot is ed machines exec tuf -- power reboot, so it looks for
a program called power on the far side and fails there. The shorthand always
means "run this on the machine", so reach for ed machines tuf ... when you
want Edith's own verb.
A machine resolves by display name, SSH config alias, id, or any unambiguous case-insensitive prefix. An unknown or ambiguous name exits 3 with the candidates in the hint, and never guesses.
Says whether the machine has a live shared connection, what MAC address is
stored for it, and which of wake and reboot are possible right now. It is the
default subcommand of power, so ed machines power tuf runs it.
ed machines power status <machine> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to report on. Resolved by name, alias, id or unambiguous prefix. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--json |
flag | off | Emit JSON on stdout instead of the table. Long form only, there is no -j. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
One row, five columns:
$ ed machines power status tuf
MACHINE CONNECTED MAC WAKE REBOOT
Asus TUF 7 yes 04:42:1a:8d:2f:6c yes yes
MAC prints - when Edith has never learned one.
{
"canReboot": true,
"canShutDown": true,
"canWake": true,
"connected": true,
"macAddress": "04:42:1a:8d:2f:6c",
"machine": "Asus TUF 7"
}machine is the display name, not the id. macAddress is null rather than
missing when none is stored, and canWake is exactly macAddress != null.
canReboot and canShutDown are both copies of connected.
ed machines power status tuf
ed machines power tuf
ed machines tuf power
ed machines power status tuf --json | jq -r '.canWake'
This is the one command on the page that never touches the network. connected
is a local test: it looks for the ControlMaster socket file for that machine and
runs ssh -S <socket> -O check against it. A machine that is up and reachable
but has no open shared connection reports connected: false, which is no in
the table.
Read that as a promise about cost, not about capability. canReboot: false
means there is no open channel to reuse, not that a reboot would be refused:
ed machines power reboot opens its own connection when there is none. What it
does tell you is that the next command will pay for a fresh SSH handshake.
Nothing is mutated. The only failure is an unknown machine, which exits 3.
Restarts the machine through systemd. Does nothing without --yes.
ed machines power reboot <machine> [--yes] [--json]
The command is also spelled ed machines power restart.
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to restart. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--yes |
flag | off | Actually restart it. Without this nothing is done. |
--json |
flag | off | Emit JSON on stdout instead of the human lines. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
Without --yes it tells you what it would do, changes nothing, and exits 0. The
line naming the machine goes to stdout and the reminder goes to stderr:
$ ed machines power reboot tuf
would restart Asus TUF 7
nothing was done; pass --yes to go ahead
With --yes it connects, runs the reboot, and reports:
$ ed machines power reboot tuf --yes
Asus TUF 7 is restarting
Two shapes, told apart by applied. Without --yes the document also carries
the exact shell line that would have run, so you can read it before you run it:
{
"action": "reboot",
"applied": false,
"command": "sudo -n systemctl reboot 2>&1 || systemctl reboot 2>&1",
"machine": "Asus TUF 7"
}With --yes, on success, command is not included:
{
"action": "reboot",
"applied": true,
"machine": "Asus TUF 7"
}action is the literal string reboot in both, even when you typed the
restart alias.
ed machines power reboot tuf
ed machines power reboot tuf --yes
ed machines tuf power reboot --yes
ed machines power restart tuf --yes --json
The remote line is sudo -n systemctl reboot 2>&1 || systemctl reboot 2>&1, so
ed tries passwordless sudo first and falls back to plain systemctl for a
machine whose polkit rules already allow it. Stderr is folded into stdout on the
far side, which is why a refusal comes back as readable prose rather than as an
empty failure.
A machine that answers a password is required or Interactive authentication
required is reported as having refused, and exits 1, rather than being called
done. The hint appears only when the output matches one of the phrases that mean
privilege: password is required, interactive authentication required,
access denied, not authorized or permission denied.
$ ed machines power reboot tuf --yes
error: Asus TUF 7 did not reboot: sudo: a password is required
Call to Reboot failed: Interactive authentication required.
hint: give this account passwordless sudo for systemctl on Asus TUF 7
The error text after the colon is the machine's own combined output, trimmed.
When the machine said nothing at all that half falls back to a second sentence
of Edith's own, so the whole line reads
error: Asus TUF 7 did not reboot: Asus TUF 7 refused to reboot.
The command waits at most 20 seconds for the remote line to return. Reaching the
machine happens first and has its own 25 second budget; a machine that cannot be
reached exits 4 with could not reach <machine> before anything is attempted.
systemctl reboot returns as soon as systemd accepts the request, which is why
the usual successful run exits cleanly before the host disappears. If ssh
instead exits non-zero because the connection died under it, that is reported as
a refusal and exits 1; see the gotcha at the end of this page.
Powers the machine off through systemd. Does nothing without --yes.
ed machines power shutdown <machine> [--yes] [--json]
The command is also spelled ed machines power poweroff.
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to shut down. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--yes |
flag | off | Actually shut it down. Without this nothing is done. |
--json |
flag | off | Emit JSON on stdout instead of the human lines. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
$ ed machines power shutdown tuf
would shut Asus TUF 7 down
nothing was done; pass --yes to go ahead
$ ed machines power shutdown tuf --yes
Asus TUF 7 is shutting down
The same two shapes as reboot, with action set to shutdown and the remote
line built from poweroff:
{
"action": "shutdown",
"applied": false,
"command": "sudo -n systemctl poweroff 2>&1 || systemctl poweroff 2>&1",
"machine": "Asus TUF 7"
}{
"action": "shutdown",
"applied": true,
"machine": "Asus TUF 7"
}ed machines power shutdown tuf
ed machines power shutdown tuf --yes
ed machines tuf power poweroff --yes
ed machines power shutdown tuf --json
Identical to reboot in every respect but the verb: same 20 second timeout,
same sudo-then-plain fallback, same refusal detection, same exit codes.
Think about the way back before you run it. A machine that is off answers
nothing, so the only verb left is ed machines power wake, and that needs a
stored MAC address and a machine whose firmware has wake-on-LAN enabled. Check
with ed machines power status <machine> first: if WAKE says no, a shutdown
is a trip to the physical power button.
Sends a wake-on-LAN magic packet to the machine's stored MAC address.
ed machines power wake <machine> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to wake. Resolved from the machine file, so it works while the machine is off. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--json |
flag | off | Emit JSON on stdout instead of the human line. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
$ ed machines power wake tuf
sent a wake packet to 04:42:1a:8d:2f:6c
{
"action": "wake",
"applied": true,
"macAddress": "04:42:1a:8d:2f:6c",
"machine": "Asus TUF 7"
}applied: true means the packet left this Mac. It is not a claim that the
machine woke.
ed machines power wake tuf
ed machines tuf power wake
ed machines power wake tuf --json
ed machines edit tuf --mac 04:42:1a:8d:2f:6c
There is no SSH here at all. ed builds the magic packet by hand, six 0xFF
bytes followed by the six address bytes repeated sixteen times, opens a UDP
socket with SO_BROADCAST, and sends it to 255.255.255.255 on port 9. That is
a limited broadcast, so it reaches the local link and no further: waking a
machine on another subnet needs a router that forwards directed broadcasts, and
this command cannot arrange that for you.
Edith learns the address the first time it sees the machine up, by reading
/sys/class/net/*/address and keeping the first entry that is not all zeroes.
Until that has happened there is nothing to send to, and the command exits 4:
$ ed machines power wake box
error: no MAC address is stored for Home Box
hint: open the machine in Edith while it is up so it can learn one, or set it with `ed machines edit Home Box --mac <address>`
The hint quotes the display name verbatim, so a name with spaces needs quoting when you retype the suggestion.
A stored value that is not six colon-separated hex pairs exits 1 with
<value> is not a MAC address, and a socket that cannot be opened or written
exits 1 with Could not open a socket. or The wake packet could not be sent..
Nothing here depends on the machine being reachable, which is the whole point of
the verb.
Lists the systemd service units on a machine. It is the default subcommand of
services, so ed machines services tuf runs it. Also spelled
ed machines services list.
ed machines services ls <machine> [--failed] [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine to list units on. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--failed |
flag | off | Only failed units, meaning those whose active or sub field is failed. Filtered on this Mac after the full list arrives. |
--json |
flag | off | Emit JSON on stdout instead of the table. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
$ ed machines services tuf
UNIT ACTIVE SUB WHAT
cron.service active running Regular background program processing daemon
docker.service active running Docker Application Container Engine
nginx.service active running A high performance web server
ollama.service failed failed Ollama Service
ssh.service active running OpenBSD Secure Shell server
systemd-timesyncd.service active running Network Time Synchronization
A top-level array, one object per unit, in the order systemctl returned them:
[
{
"active": "active",
"description": "A high performance web server",
"failed": false,
"load": "loaded",
"running": true,
"sub": "running",
"unit": "nginx.service"
},
{
"active": "failed",
"description": "Ollama Service",
"failed": true,
"load": "loaded",
"running": false,
"sub": "failed",
"unit": "ollama.service"
}
]load, active and sub are systemd's own three columns, passed through
untouched. running is sub == "running" and failed is
active == "failed" || sub == "failed", both precomputed so a script does not
have to know systemd's vocabulary. The JSON key is description; the table
column is headed WHAT.
ed machines services tuf
ed machines services ls tuf --failed
ed machines tuf services ls
ed machines services ls tuf --json | jq -r '.[] | select(.failed) | .unit'
The remote line is this, with a 30 second timeout:
systemctl list-units --type=service --all --no-pager --no-legend --plain 2>/dev/null | head -200
Three consequences worth knowing.
The list is capped at 200 units and there is no flag to raise it. A machine with more services than that loses the tail silently.
Only .service units are listed. Timers, sockets, mounts and targets are not,
because the parser drops any line whose first field does not end in .service.
A machine with no systemd at all reports nothing rather than failing. The
2>/dev/null swallows the "command not found" and head exits 0, so you get a
note on stderr and exit 0:
$ ed machines services ls box
no systemd units reported
--failed narrows the list here, on this Mac, after all 200 lines have crossed
the wire. It is not systemctl --failed, so it costs the same as the full list.
Starts one unit.
ed machines services start <machine> <unit> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine the unit lives on. |
<unit> |
unit name | required | The unit, for example nginx.service. Quoted for the remote shell only when it holds something outside letters, digits and ._-+/=:@%,, so a name with awkward characters survives. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--json |
flag | off | Emit JSON on stdout instead of the human line. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
$ ed machines services start tuf nginx.service
started nginx.service on Asus TUF 7
{
"action": "start",
"applied": true,
"machine": "Asus TUF 7",
"unit": "nginx.service"
}This document is only ever emitted on success. A failure writes nothing to stdout and reports on stderr instead.
ed machines services start tuf nginx.service
ed machines tuf services start docker.service
ed machines services start tuf nginx.service --json
There is no --yes on the unit verbs. They act immediately.
The remote line for nginx.service is
systemctl start nginx.service 2>&1 || sudo -n systemctl start nginx.service 2>&1,
with a 60 second timeout. The unit is only wrapped in single quotes when it holds
a character outside letters, digits and ._-+/=:@%,, so an ordinary name goes
across bare. Note the order: plain systemctl first, sudo -n as the fallback,
which is the opposite way round from reboot and shutdown.
Systemd's own unit name shorthand applies, because ed passes the name straight
through: nginx and nginx.service are the same unit to systemctl start. The
.service suffix is what ed machines services ls prints, so it is the safe
thing to copy.
A failure exits 1 with the machine's output appended, and adds the sudo hint only when the output looks like a privilege problem:
$ ed machines services start tuf nginx.service
error: could not start nginx.service on Asus TUF 7: Failed to start nginx.service: Unit nginx.service not found.
An unreachable machine exits 4 before the unit is touched. An unknown machine
name exits 3. A unit that does not exist is a remote failure, so it exits 1, not
3: ed never checks the unit list before acting.
Stops one unit.
ed machines services stop <machine> <unit> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine the unit lives on. |
<unit> |
unit name | required | The unit, for example nginx.service. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--json |
flag | off | Emit JSON on stdout instead of the human line. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
The same four keys, with action set to stop:
{
"action": "stop",
"applied": true,
"machine": "Asus TUF 7",
"unit": "nginx.service"
}ed machines services stop tuf nginx.service
ed machines tuf services stop ollama.service
ed machines services stop tuf nginx.service --json
The most disruptive command on this page that has no confirmation flag. Stopping
ssh.service on a machine you reach over SSH is the obvious way to lock
yourself out, and ed will not stop you.
The human success line is built by appending ed to the verb, so stop prints
stoped nginx.service on Asus TUF 7, with one p. Match on the JSON if you are
scripting against this, not on the prose.
Everything else matches start: same command shape with the verb swapped, same
60 second timeout, same failure handling and exit codes.
Restarts one unit.
ed machines services restart <machine> <unit> [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine the unit lives on. |
<unit> |
unit name | required | The unit, for example nginx.service. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--json |
flag | off | Emit JSON on stdout instead of the human line. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
$ ed machines services restart tuf nginx.service
restarted nginx.service on Asus TUF 7
{
"action": "restart",
"applied": true,
"machine": "Asus TUF 7",
"unit": "nginx.service"
}ed machines services restart tuf nginx.service
ed machines tuf services restart docker.service
ed machines services restart tuf nginx.service --json
systemctl restart on a stopped unit starts it, so this is the verb to reach
for when you do not care what state the unit was in. The 60 second timeout is
the one to watch: a unit with a slow ExecStop can outlast it, and the command
then reports a failure for something that finishes fine a moment later.
Only start, stop and restart exist. There is no enable, disable,
reload, status or journal verb; for those, use the raw form,
ed tuf systemctl reload nginx or ed tuf journalctl -u nginx -n 100.
Sends a signal to one process on a machine.
ed machines kill <machine> <pid> [--signal <name>] [--json]
| Name | Type / values | Default | What it does |
|---|---|---|---|
<machine> |
machine name, ssh alias or id | required | Which machine the process is on. |
<pid> |
integer greater than 0 | required | The process id. A value that is not an integer exits 2; zero or negative exits 1. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--signal |
TERM, KILL, HUP, INT, QUIT, USR1, USR2
|
TERM |
Which signal to send. Case-insensitive, and a leading SIG is stripped, so kill, KILL, sigkill and SIGKILL are all the same. Anything else exits 3. |
--json |
flag | off | Emit JSON on stdout instead of the human line. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
$ ed machines kill tuf 4213
sent SIGTERM to 4213 on Asus TUF 7
{
"machine": "Asus TUF 7",
"pid": 4213,
"sent": true,
"signal": "KILL"
}signal is the normalised name without the SIG prefix, whatever you typed.
sent: true means the remote kill exited 0; it is not a claim that the
process is gone, which for TERM is up to the process.
ed machines kill tuf 4213
ed machines kill tuf 4213 --signal KILL
ed machines tuf kill 4213 --signal HUP
ed machines metrics tuf --processes 20 --json | jq -r '.sample.processes[] | "\(.pid) \(.name)"'
ed machines metrics <machine> --processes 20 is how you find the pid; the
collector sends at most thirty processes, the busiest by CPU plus the largest by
memory, in no particular order, and --processes trims that list rather than
asking for more. There is no name matching here on purpose: this verb takes a
number, so it cannot kill the wrong thing because two processes shared a name.
The signal name is checked on this Mac before anything is sent, so a typo costs nothing and never reaches the remote shell:
$ ed machines kill tuf 4213 --signal BOOM
error: there is no signal called BOOM
hint: signals: TERM, KILL, HUP, INT, QUIT, USR1, USR2
The remote line is kill -<SIGNAL> <pid> 2>&1, run through the login shell with
a 30 second timeout, so it runs as the SSH user and is subject to that user's
permissions. There is no sudo fallback here, unlike the unit verbs: signalling
another user's process comes back as Operation not permitted and exits 1.
$ ed machines kill tuf 1
error: could not signal 1 on Asus TUF 7: bash: line 1: kill: (1) - Operation not permitted
A pid that no longer exists is also a remote failure and exits 1, with the
shell's No such process in the message. Zero and negative ids are rejected
locally with a process id is greater than zero and exit 1, though a negative
one needs -- to get past the parser at all: a bare ed machines kill tuf -1
reads -1 as an unknown option and exits 2, while ed machines kill tuf -- -1
reaches the check and exits 1.
Runs one command on every configured machine, one after another, and labels each machine's output.
ed machines broadcast [--only <a,b>] [--json] [--] <command...>
| Name | Type / values | Default | What it does |
|---|---|---|---|
<command...> |
everything remaining | required | The command to run everywhere. Captured verbatim to the end of the line, joined with single spaces. A leading -- is dropped. |
| Name | Type / values | Default | What it does |
|---|---|---|---|
--only |
comma-separated machine names | unset, meaning every configured machine | Restrict to these machines. Each entry is trimmed of surrounding spaces and resolved like any machine name, so aliases and prefixes work. |
--json |
flag | off | Emit JSON on stdout instead of the labelled blocks. |
--help, -h
|
flag | off | Print the help for this command on stdout and exit 0. |
Flags belong before the command, because everything from the first non-flag word
onwards is the command. Use -- to make that boundary explicit:
$ ed machines broadcast -- uptime
== Asus TUF 7 ==
22:14:03 up 6 days, 3:41, 2 users, load average: 0.42, 0.51, 0.48
== Home Box ==
22:14:05 up 19:02, 1 user, load average: 0.08, 0.03, 0.01
A machine whose command failed still shows its output, and the exit note goes to stderr:
$ ed machines broadcast --only tuf,box -- docker ps -q
== Asus TUF 7 ==
b556d7fef23e
f8968a8b81e5
== Home Box ==
bash: line 1: docker: command not found
Home Box exited 127
A top-level array, one object per machine, in the order they were tried:
[
{
"machine": "Asus TUF 7",
"output": "b556d7fef23e\nf8968a8b81e5",
"status": 0
},
{
"machine": "Home Box",
"output": "bash: line 1: docker: command not found",
"status": 127
},
{
"machine": "Pi 4",
"output": "The operation couldn’t be completed. (EdithCLI.CLIFailure error 1.)",
"status": -1
}
]status is the remote exit code, or -1 when the machine could not be reached
or the connection broke mid-command. output is stdout and stderr concatenated
and trimmed, and for a -1 row it is Foundation's generic description of the
error rather than the reachability message you would get from
ed machines connect, so treat a -1 as "could not run", not as text worth
parsing.
The whole array is emitted at the end, in one document. In the human form the blocks stream as each machine finishes.
ed machines broadcast -- uptime
ed machines broadcast --only tuf,box -- df -h /
ed machines broadcast --json -- 'systemctl is-system-running' | jq -r '.[] | "\(.machine) \(.output)"'
ed machines broadcast -- 'apt list --upgradable 2>/dev/null | wc -l'
This is the terminal's broadcast bar as a command, aimed at every configured machine rather than at the open panes. Machines are contacted one at a time, not in parallel, each with its own 120 second timeout, so a run across five machines can take ten minutes in the worst case. Each one opens or reuses the shared ControlMaster socket, so a sleeping host is dialled rather than skipped.
A machine that cannot be reached is reported and the rest still run. That is the point of the verb: one unreachable host does not cost you the other answers.
The exit code is 1 if any machine returned a non-zero status, including the -1
rows. It is the one command in this group that writes real output to stdout and
still exits non-zero, so gate on the exit code first and read the array second.
Arguments are joined with a single space and sent as one line to the remote shell, which means shell metacharacters are the machine's to interpret, not yours. Quote the whole line when you want a pipe, a redirect or a glob to run over there, as in the last example above.
Failure to give a command at all exits 2 from the parser. A command that is only
whitespace, or a bare --, exits 1 with give a command to run. With no
machines configured it exits 3:
$ ed machines broadcast -- uptime
error: no machines are configured
hint: add one with `ed machines add`
--only resolves every name before any command runs, so one bad name exits 3
and nothing is executed anywhere. Names may repeat, and the machine then runs
the command twice.
| Code | When |
|---|---|
| 0 | The command did what it says. Also the dry run of reboot and shutdown without --yes, services ls on a machine with no systemd, and --help on any of these. |
| 1 | The machine refused a reboot or shutdown; a unit verb failed or came back with a privilege message; kill was rejected by the far side or given a pid of zero or less; the wake packet could not be built or sent; broadcast had at least one machine return non-zero; broadcast was given an empty command. |
| 2 | The command line was wrong: an unknown flag, a missing machine, unit or command, or a pid that is not an integer. |
| 3 | The machine name is unknown or an ambiguous prefix; --signal named something that is not one of the seven; broadcast found no machines configured, or --only named a machine that does not exist. |
| 4 | The machine could not be reached, which covers every verb that opens a connection; or wake was asked for a machine with no stored MAC address. |
broadcast never exits 4 for an unreachable machine, because reaching some and
not others is the case it exists to handle. That failure becomes a -1 row and
folds into the overall exit 1.
None of these codes ever comes from Edith not running. Nothing on this page talks to the app.
- Nothing here needs the Edith app or the menu bar helper.
statusreads the machine file under~/Library/Application Support/Edithand the control socket;wakeopens a UDP socket; everything else is/usr/bin/ssh. No macOS permission is involved either, so exit 4 on this page always means the machine is unreachable or unknown to wake-on-LAN, never that Edith is closed. - The privilege fallback runs in different orders in the two families.
rebootandshutdowntrysudo -n systemctl ...first and fall back to plainsystemctl. The unit verbs try plainsystemctl ...first and fall back tosudo -n. Both fold stderr into stdout with2>&1, so both attempts' output arrives in one string. - That has a sharp edge on the unit verbs. Because the first attempt's output is
still in the buffer, a
startthat only succeeded through the sudo fallback can carry the first attempt's Interactive authentication required text, and the presence of that phrase alone is enough foredto call it a failure. The unit changes state on the machine andedexits 1 saying it could not. If you see that, check withed machines services ls <machine>before retrying. - The phrases that count as a privilege problem are
password is required,interactive authentication required,access denied,not authorizedandpermission denied, matched case-insensitively anywhere in the output. A unit whose own log line happens to contain one of them is judged the same way. -
power statusanswers about the control socket, not about the machine.connected: falseon a machine that is up simply means no shared connection is open yet, and the next command will open one. - A reboot that takes the connection down with it is meant to be treated as
success, and the code has a branch for exactly that, keyed on ssh reporting
status 255 or a closed connection. That branch only fires for an error thrown
by the SSH layer, and the layer returns the exit status instead of throwing
it, so in practice an ssh that exits 255 because the host vanished is reported
as a refusal and exits 1. The normal case is unaffected, because
systemctl rebootreturns 0 before the host goes down. -
--yesexists onrebootandshutdownonly.services stop,killandbroadcastare all capable of taking a machine off the network and none of them asks first. - Object keys in every
--jsondocument on this page are sorted lexicographically, and each invocation prints exactly one document, so output diffs cleanly andjqnever sees a stream.--jsonis declared per command and is long-form only; there is no-j. - A failing command prints nothing on stdout, with one exception:
ed machines broadcastprints its blocks or its array and then exits 1 when a machine failed. -
ed machines powerwith no verb and no machine exits 2, because the default subcommand still wants a machine.ed machines power <machine>ised machines power status <machine>, anded machines services <machine>ised machines services ls <machine>. - Aliases:
power rebootis alsopower restart,power shutdownis alsopower poweroff, andservices lsis alsoservices list. Theactionfield in JSON always carries the canonical name,rebootorshutdown. - Shell completion knows this whole subtree, including machine names in the machine slot. It does not complete unit names or pids, because those would need a round trip to the machine.
-
ed machinesfor the machine directory itself, includinged machines edit <machine> --mac <address>to teachwakean address, anded machines metricsfor the process listkillneeds. -
Running commands on a machine for the raw form, which
is where
systemctl enable,journalctland anything else not covered here belongs. -
ed machines dockerfor the container equivalents of start, stop, restart and rm. -
ed machines filesfor moving things onto and off a machine. -
Conventions and contracts for the full exit code table and
the
--jsonguarantee. -
The
edcommand line for the rest of the reference.
Auto-generated from docs/, edit the docs in the repo, not the wiki.
CLI reference
Companion
- Deploy
- Concepts
- Concepts Memory
- Concepts Ingestion
- Concepts Search
- Concepts Chat
- Concepts Learning
- Concepts Brain
- Concepts Friend
- Hosts
- Stack
- Status
- Doctor
- Search
- Index
- Ingest
- Episodes
- Sync
- Observations
- Reflect
- Beliefs
- Ask
- Extract
- Claims
- Corroborate
- Runs
- Chat
- Conversations
- Forget
- Export
- Import
- Erase
- Wipe
- Episode
- Nightly
- Reason
- Personas
- Council
- Lenses
- Core
- Why
- Hypotheses
- Predictions
- Commitments
- Discrepancies
- Calibration
- Inquire
- Entities
- Eval
- Standup
- Machines
- Baselines
- Connectors
- Facts
- Correct
- Weekly
- Db
Guides