Approvals and rules
An approval is your decision on an action that your AI coding agent asks the SSH gateway to run: you approve it, reject it or always allow it. The SSH gateway is the part of Athenode through which your AI agent runs commands and transfers files on your SSH hosts, each action approved by you or by a rule you set. A connection is one SSH host in the SSH gateway, with its login, its host key and its rules, as the SSH gateway overview describes.
Three settings decide whether an action waits for you: the confirmation mode of the connection or of the session, the allow rules that let matching actions run without asking, and the denylist, whose matches always wait. Every action needs a reason from the agent, which is shown above the command when you decide.
| Action | Goes through approval |
|---|---|
exec, start_job |
Yes, matched as a command |
cancel_job |
Yes, matched as cancel_job followed by the job's command |
read_file, write_file, list_dir, upload, download |
Yes, matched as the tool followed by the remote path |
add_service, update_service that create or change a health check |
Yes, matched like an exec of the check's command |
job_status, job_logs, exec_output, service_health, run_service_check |
No. They run at once and appear in History |
Approvals, allow rules and the denylist are managed in the web UI only. No tool of the Athenode MCP server reads or changes them, and no CLI command does.
Choose the confirmation mode of a connection
The confirmation mode of a connection decides what happens to an action that no allow rule covers. You set it when the agent's work on a host should wait for you, or run on its own. On Athenode Pro you need the owner role in the project, as project roles lists.
| Mode | Label | What it does |
|---|---|---|
confirm |
Require confirmation | Every action waits for your approval, unless all of it matches allow rules. A new connection has this mode. |
auto |
Auto | Every action runs without asking, except those that match the denylist. |
- Open Connections in the SSH Gateway group of the sidebar and select the connection.
- Open the Settings tab.
- Under Behaviour, at Default confirmation mode, choose Require confirmation or Auto.
- Select Save changes.
The mode applies to the sessions that do not override it. An action takes the mode that applies when it arrives, so a change does not release actions that are already waiting.
Change the confirmation mode of one session
A session is the work of one AI tool session on one connection. Each session has its own window, listed under its connection in the sidebar, and it can override the connection's mode, for example to let one agent run a series of checks without asking while other sessions keep asking.
- Open the session: select it under its connection in the sidebar, or select one of its actions on the Live or History page.
- At Confirmation mode in the session's header, choose Auto or Confirm. Connection default returns the session to the connection's mode, which it shows in brackets.
The new mode applies to the actions that arrive afterwards. An action already waiting keeps waiting for your decision. A new session of the AI tool starts with the connection's mode again. On Athenode Pro only the account whose agent runs the session can change its mode, and everyone else sees the mode as text.
Approve or reject an action
An action that needs approval waits until you decide, until the approval timeout ends or until the AI tool cancels the call. Athenode tells you about it in several places:
- The header of the web UI shows "An action is waiting for your approval." with the number of waiting actions, and Review opens the session of the oldest one.
- The browser tab's title starts with the number in brackets, such as
(2). - The Live page lists every action that is waiting or running, across all sessions of the project, with the agent's reason, the command, the connection, the session and the tool.
- With desktop notifications on, the browser shows "Approval needed:" followed by the connection's name. Turn them on under Notifications on the Settings page with Allow. The choice applies to that browser only.
To decide:
- Open Live and select the waiting action. An action you can decide is marked "Open to decide".
- In the session window, read the reason and the command.
- Select Approve to run the action, Reject to refuse it, or Always allow… to approve it and save an allow rule, as allow an action from now on describes.
The first decision counts. If the action was decided in another tab or window, or has timed out, the session window shows "Already decided" and nothing runs. On Athenode Pro only the account whose agent asked decides, administrators included, and everyone else sees "Waiting for the decision of the user whose agent asked." The gateway on Athenode Pro describes who sees which sessions.
What the agent receives for each outcome
| Outcome | What happens | What your AI agent receives | Status of the action |
|---|---|---|---|
| Approved | The action runs | The result of the action | Running, then Done or Failed |
| Rejected | Nothing runs | "Rejected by user" | Rejected |
| Timed out | Nothing runs | "Approval timed out after 10m", with the approval timeout in force | Timed out |
| Cancelled by the AI tool | Nothing runs | "Cancelled by the client" | Cancelled |
| Athenode stopped while the action waited | Nothing runs | "SSH Gateway is shutting down" | Aborted, after the next start |
The approval timeout is 10 minutes. It starts when the action arrives and does not restart. You change it on the Settings page, as History and gateway settings lists, and the new value applies to actions that arrive afterwards. An action that was running when Athenode stopped shows Interrupted after the next start.
The agent's result never says that an action matched the denylist, and no tool shows the denylist to the agent.
Keep your AI tool waiting during an approval
Your AI tool has its own time limit for a tool call, and an action that waits for you counts towards it. While an action waits, Athenode tells the AI tool every 15 seconds that the call is still in progress. The AI tool's own limit still applies, so set it above the approval timeout.
In Claude Code, set MCP_TOOL_TIMEOUT in milliseconds before you start it. With the approval timeout of 10 minutes, 15 minutes leaves room:
MCP_TOOL_TIMEOUT=900000 claudeFor an AI tool with a fixed limit of its own, set the approval timeout below that limit. When the AI tool gives up first, the action ends as Cancelled and nothing runs.
Allow an action from now on
Always allow… approves the waiting action and saves a pattern as an allow rule of the connection, so matching actions run without asking from then on. Use it for commands you would approve every time, such as systemctl status nginx.
- In the session window of the waiting action, select Always allow….
- Read the pattern Athenode proposes. For a command it is the first word followed by
*, such asdf *, or the first two words forgit,docker,systemctl,kubectl,apt,apt-get,npm,pnpmandyarn, such assystemctl status *. For a file tool it is the tool and the file's folder, such asread_file /var/log/nginx/*. For a cancellation it iscancel_job *. - Optional: edit the pattern. Below it, "Matches this action" or "Does not match this action" says whether the pattern covers the waiting action, with the reason when it cannot.
- Select Always allow.
The action runs and the rule appears on the connection's Rules tab. Other actions that are already waiting stay waiting. Always allow… is not offered for an action that matches the denylist: the session window names the denylist patterns it matched.
On Athenode Pro, Always allow for you saves a personal rule that applies to your own actions only. Personal rules and the global allow rules are described on the gateway on Athenode Pro.
Add or remove allow rules of a connection
The allow rules of a connection are the patterns under which actions run without asking on that connection. Write them in advance when you know what the agent will run. On Athenode Pro you need the owner role in the project.
- Open the connection and its Rules tab.
- Under Always allow, enter a pattern at New always-allow rule, such as
systemctl status *. - Select Add.
To remove a rule, select its delete button. A rule that matches a file tool is tagged File. An invalid pattern is refused with the reason, such as "The pattern is longer than 1000 characters". The rules of a connection go with it when you copy it to another project, as the SSH gateway overview describes.
Write a rule pattern
A pattern is the text that an allow rule or a denylist entry matches. Allow rules and the denylist use the same patterns, in three forms. A pattern holds up to 1,000 characters.
| Form | Written as | Matches |
|---|---|---|
| Command glob, the default | systemctl status * |
The whole command. * matches any text, / included, and ? one character. Everything else is literal. A trailing * also matches the command on its own, so ls * matches ls and ls -la /etc |
| Regular expression | /^journalctl -u [a-z-]+$/, or /…/i to ignore case |
Any part of the command, so anchor it with ^ and $. Backreferences and lookaround are refused |
| File rule | read_file /var/log/** |
That file tool only, on the remote path. The tools are read_file, write_file, list_dir, upload and download. * matches within one folder and ** across folders. A * does not match a name that starts with a dot |
Command patterns never match a file tool, and file rules never match a command. These rules decide what a command pattern is compared with:
- Spaces between words count as one space, a leading
commandor\is dropped, and/usr/bin/tailcounts astail. Leading assignments such asLANG=Care dropped too. - A command run with sudo is matched as
sudofollowed by the command.ls *does not approvelswith sudo, andsudo ls *does. - A command joined with
&&,||,;,|or&is approved by allow rules only when each part matches one.cd /srv/shop && git pullneeds rules for bothcd /srv/shopandgit pull. The commands inside$(…),<(…)and>(…)count as parts too. - A file path is matched as the agent gave it, with
.,..and repeated slashes resolved. A path relative to the home folder stays relative, soread_file ~/shop/*andread_file /home/deploy/shop/*are separate rules. - A cancellation is matched as
cancel_jobfollowed by the command of the job.
Actions that no allow rule approves
Some commands can run something that their text does not show. An action that contains one of these always waits for approval in confirm mode, whatever the allow rules say, and in auto mode it runs like any other action that is not on the denylist:
- Backticks,
$expansions outside single quotes such asrm $FILE, heredocs, comments, line breaks and unbalanced quotes. - Output redirection to anything other than
/dev/null. - A command that runs other commands:
bash,sh,zsh,dash,ksh,eval,exec,xargs,env,nohup,timeout,nice,ssh,sourceand.. findwith-exec,-execdir,-okor-okdir.- Setting
LD_PRELOAD,LD_LIBRARY_PATH,BASH_ENV,ENV,PATHorPROMPT_COMMAND, in the command or through the action's environment. - A file path that climbs above its starting folder, such as
~/../../etc/shadow.
When you choose Always allow… for such an action, the pattern preview says "Does not match this action" and lists the reasons.
Edit the denylist
The denylist is the list of patterns whose actions always need approval, in auto mode and over any allow rule, and can never be always allowed. The global denylist applies to every connection of every project on the server. On Athenode Pro it belongs to the administrators.
- Open Settings in the sidebar, outside a project.
- Go to Denylist.
- Enter a pattern at New denylist pattern, such as
terraform destroy*, and select Add. To remove a pattern, select its delete button.
A new server starts with eight patterns, tagged Default:
| Pattern | Catches |
|---|---|
rm -*r* |
Recursive deletion with a short option, such as rm -rf |
rm --recursive* |
Recursive deletion with the long option |
mkfs* |
Creating a file system |
dd * |
Raw copies to and from devices |
shutdown* |
Shutting down |
reboot* |
Restarting |
poweroff* |
Powering off |
halt* |
Halting |
You can remove the default patterns like any other, and a removed one does not come back. A denylist pattern matches more widely than an allow rule. It matches each part of a command, also with a leading sudo and its options removed, and anywhere in the command at the start of a word, so rm -*r* catches bash -c "rm -rf /tmp/build". A denylist pattern can also be a file rule, such as write_file /etc/**.
Change the denylist for one connection
A connection can add patterns to the global denylist, and switch global patterns off for itself. Add patterns for a host where more commands deserve a second look, such as a production database. On Athenode Pro, adding patterns needs the owner role in the project, and switching global patterns off is for administrators.
To add a pattern for one connection:
- Open the connection and its Rules tab.
- Under Always ask, enter a pattern at New denylist addition, such as
pg_dump *. - Select Add.
To switch a global pattern off for one connection:
- On the same tab, go to Global denylist on this connection.
- Switch on the entry of the pattern. It shows "disabled here".
On that connection, matching actions then follow the mode and the allow rules. Other connections keep the pattern, and the connection's own additions still apply. Deleting the global pattern removes the switch with it.