agent-lookout 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,36 @@
2
2
 
3
3
  Changes that a user of Agent Lookout would notice, newest first.
4
4
 
5
+ ## 0.2.6 - 2026-10-07
6
+
7
+ Set rules that answer Claude Code's permission prompts for you, run Agent Lookout on Windows, and see a prompt you answered leave Needs you at once.
8
+
9
+ ### Added
10
+
11
+ - Permission rules, a card in Settings under Permission prompts. Decide once how a kind of Claude Code permission prompt is answered: always allow, always ask or always deny, by tool and, for Bash, by command, exactly or as a prefix written as Claude Code writes one, such as `npm test:*`. Add, edit, move up and down, and remove rules there; Agent Lookout keeps them in `~/.agent-lookout/settings.json`. Deny goes first, then ask, then allow, as in Claude Code's own rules. A deny or an allow rule answers a matching request at once through the plugin, with every check Allow and Deny make. An allow rule answers only what you could allow by hand, and for Bash only one plain command: a line with `;`, `&&`, `|`, `$( )`, a variable, quotes or a redirection in it waits for you, and no allow rule can begin with a program that runs another, such as `sudo`, `env` or `bash`, or with one that sends requests or runs the code it is given, such as `curl`, `ssh`, `node` or `python`, through which Claude could reach Agent Lookout itself and add a rule. A rule for a package manager or a build tool names its subcommand, such as `npm test:*`, never `npm:*`. Nor does an allow rule answer a subcommand on its list that fetches or runs code, such as `npm exec` or `docker run`, an option through which a program runs another, such as `git -c`, or a command that names Agent Lookout's own folder, its settings file or socket, or a folder above them, and it answers no command of a session whose folder is your home folder or above. A deny or an ask rule finds its words in any command of the line, with options between them, so `git push:*` also holds back `git -C . push`, and can name every tool of an MCP server, such as `mcp__docs`. Each answer is in the Events log with the rule, never the command, and the card lists the last 100. Unless a read of Claude Code's file in the instant before the plugin's request arrives saw the wait begin, a prompt a rule answers sends no notification, email, webhook post or reminder, does not light the lamp or come into Needs you, its count, the tab's title, the Mac app's Dock badge and menu bar, or what `agent-lookout status` and `agent-lookout mcp` count as needing you, and Waits does not count it: for the second or two before Claude Code says what it does next, the session is listed with the working sessions as Answered. A computer that reads this one over SSH takes the wait as answered too. A deny or an allow rule in Claude Code's own settings still decides first. There is no rule until you add one, and rules answer Claude Code sessions with the plugin only. [Permission rules](docs/GUIDE.md#permission-rules) has the details.
12
+ - `GET /api/settings` gives the permission rules and the requests they answered since Agent Lookout started, and `POST /api/settings/permission-rules` makes one change to them. No page on another site can send it, though another program on this computer can, as [Permission rules](docs/GUIDE.md#permission-rules) warns. The Mac app has no such route, but it takes up at its next poll a change another copy saved in the settings file. An `answered` event a rule gave has `tool` and `rule`.
13
+
14
+ #### On Windows
15
+
16
+ - Agent Lookout runs on Windows, started the same way, with `npx agent-lookout`, and reading the same folders in your user folder: `.claude\sessions`, `.codex` and `.agent-lookout\sessions`. It has been checked in CI on Windows by running the tests, less those of what Windows does not have, such as POSIX signals and Unix sockets, and by starting it with `npm start` and reading back its sessions, and not yet by a person on a Windows desktop. The guide's [On Windows](docs/GUIDE.md#on-windows) part says what works there.
17
+ - The `claude` command is looked for as `claude.exe` on `PATH`, in `%USERPROFILE%\.local\bin` and in npm's folder, `%APPDATA%\npm`. For the `claude.cmd` that npm makes, Agent Lookout runs the `claude.exe` that it runs, and it never runs a `.cmd` or a `.bat`, which need a shell.
18
+ - Stop, ending the sessions left running, Allow and Deny, the permission rules, Resume, Jump to a tmux pane or a tab of Terminal or iTerm2, and notifications with no dashboard tab open are not offered on Windows. What each agent can report, in Sources, says why for Stop, Answer and Jump, and the guide's On Windows part says why for each.
19
+ - `--open` opens the page in your default browser on Windows too.
20
+
21
+ ### Changed
22
+
23
+ - After you press Allow or Deny, the session leaves Needs you at once, and with it the lamp, the Needs you count, the tab's title and the Mac app's Dock badge and menu bar. For the second or two before Claude Code says what it does next, it is listed with the working sessions as Answered, `agent-lookout status` and `agent-lookout mcp` count it as working, and `GET /api/sessions` marks it `answered: true`. A computer that reads this one over SSH takes the wait as answered too.
24
+
25
+ ### Fixed
26
+
27
+ - A background job you stopped could still show as working, with Stop, after its details said it was stopped, until Claude Code had ended its process and the sessions were read again. Agent Lookout now waits up to 10 seconds for that process to end before it answers, as it does after SIGTERM.
28
+ - A Claude Code session whose registry file was read while it was being written dropped out of the list for a poll, which read as the session ending and starting again. What the file held at the read before now stands for it, once.
29
+ - The Python example in [Your own agents](docs/GUIDE.md#your-own-agents) stopped at once on Windows, which has no `SIGHUP`. It runs there now.
30
+ - A long wait reminder could still go out just after you pressed Allow or Deny, when its minutes were up before Claude Code's file said the session had moved on. A wait is now over from the moment it is answered, on every channel.
31
+ - With `NODE_TLS_REJECT_UNAUTHORIZED=0` in the environment, an email, and the password in `AGENT_LOOKOUT_SMTP_URL`, went to a mail server whose certificate was not checked. The certificate is now checked whatever that variable says, as the webhook's always was.
32
+ - With two copies running at once, such as the Mac app and `npx agent-lookout`, each kept the rules it read as it started, and a change saved in one could be undone by the next change in the other. Each now reads the settings file again before a change, makes the change to what the file holds, and picks up the other's change at its next poll. The Time rules card saves all three rules at once, so a time rule changed in one copy in the second or two before the other's change has reached it still puts that change back.
33
+ - With the answer socket not opened, as beside another copy of Agent Lookout that answers already, `POST /api/permission/answer` got 404 for every answer. It now gets 405, as with answering off.
34
+
5
35
  ## 0.2.5 - 2026-10-07
6
36
 
7
37
  Answer a Claude Code permission prompt from the dashboard, watch the sessions on another machine over SSH, copy the command that resumes a finished session, and set reminders, quiet hours and how long a session is idle before it counts as stale.
package/PRIVACY.md CHANGED
@@ -2,23 +2,23 @@
2
2
 
3
3
  Agent Lookout runs on your machine and reads a small amount of metadata about your Claude Code and Codex sessions, and about the sessions of any agent that writes a status file for Agent Lookout to read, and which git branch each session's folder has checked out. By default Agent Lookout itself sends nothing anywhere. Email notifications are off unless you set them up. Once you do, it sends a short email when a session has waited, and, if you choose, when one finishes, fails or ends, through the mail server you name, to the address you name, and nothing else. [Email](#email) says what one holds. Webhook posts are off unless you set an address for them. Once you do, it sends the same notices as short JSON posts to that one address, such as a Slack channel's incoming webhook, and nowhere else. [Webhook](#webhook) says what one holds. The Mac app, and only the Mac app, asks GitHub about once a day whether a newer version of it has been released, unless you turn that off in Settings. It sends nothing about your sessions: [Updates (Mac app only)](#updates-mac-app-only) says what it sends. The npm package, `npx agent-lookout` and the repository never check for anything. Pull requests are off unless you start Agent Lookout with `AGENT_LOOKOUT_PULL_REQUESTS=on`. Then it runs your own GitHub CLI, `gh`, which sends GitHub the owner and name of a session's repository and the name of its branch, with `gh`'s own login, which Agent Lookout never reads: [`gh`](#gh) says what it sends and when. Other machines are read only once you name them in `AGENT_LOOKOUT_REMOTES`. Then it runs your own `ssh` to each and asks the Agent Lookout running there for its sessions, and sends nothing of this computer's: [Another machine over SSH](#another-machine-over-ssh) says what is read. It does run Claude Code's own listing command, which may contact Anthropic the way Claude Code normally does. Its MCP server, `agent-lookout mcp`, runs only once you add it to an agent's app, and answers that app and nothing else. That app may pass what it learns to its model: [The MCP server](#the-mcp-server) says what an answer holds.
4
4
 
5
- For a Claude Code session that is waiting for you, Agent Lookout reads the last message of its transcript, to show what the session is asking, such as the command it wants to run or the question it put to you. It reads nothing of a transcript while the session is not waiting, and keeps nothing of it once the wait ends. It sends that line off the machine only if you turn it on for email, with `AGENT_LOOKOUT_EMAIL_ASKING=on`, or for the webhook, with `AGENT_LOOKOUT_WEBHOOK_ASKING=on`, and then only in the email or post for that wait. No answer of `agent-lookout mcp` holds it. [Claude Code's transcripts](#claude-codes-transcripts) says exactly what is read, and `AGENT_LOOKOUT_WAITING_TEXT=off` turns it off.
5
+ For a Claude Code session that is waiting for you, Agent Lookout reads the last message of its transcript, to show what the session is asking, such as the command it wants to run or the question it put to you. It reads nothing of a transcript while the session is not waiting, and keeps nothing of it once the wait ends. It sends that line off the machine only if you turn it on for email, with `AGENT_LOOKOUT_EMAIL_ASKING=on`, or for the webhook, with `AGENT_LOOKOUT_WEBHOOK_ASKING=on`, and then only in the email or post for that wait. It also goes to another computer that names this one in `AGENT_LOOKOUT_REMOTES` and reads its sessions over SSH. That computer shows it, and its own email and webhook settings decide whether it is sent on, as [Another machine over SSH](#another-machine-over-ssh) says. `AGENT_LOOKOUT_WAITING_TEXT=off` on this computer keeps it from there too. No answer of `agent-lookout mcp` holds it. [Claude Code's transcripts](#claude-codes-transcripts) says exactly what is read, and `AGENT_LOOKOUT_WAITING_TEXT=off` turns it off.
6
6
 
7
7
  For Codex, Agent Lookout opens Codex's session files, which hold the whole conversation. It reads them to find when each turn started and ended, and keeps only that and the few fields listed below. It keeps no prompt, reply, command or output.
8
8
 
9
- Agent Lookout stops a Claude Code session only when you press Stop in its details and confirm, or end the sessions left running after a confirmation that lists each one. It answers a Claude Code permission prompt only when you press Allow or Deny, and only with its Claude Code plugin installed. It never acts on a session on its own. [Stopping a session](#stopping-a-session) and [The Claude Code plugin and permission prompts](#the-claude-code-plugin-and-permission-prompts) say what it checks first and what it runs.
9
+ Agent Lookout stops a Claude Code session only when you press Stop in its details and confirm, or end the sessions left running after a confirmation that lists each one. It answers a Claude Code permission prompt only when you press Allow or Deny, or when a [permission rule](#permission-rules) you added in Settings decides it, and only with its Claude Code plugin installed. It never acts on a session on its own. [Stopping a session](#stopping-a-session) and [The Claude Code plugin and permission prompts](#the-claude-code-plugin-and-permission-prompts) say what it checks first and what it runs.
10
10
 
11
11
  ## What it reads and runs
12
12
 
13
13
  ### Claude Code's session registry
14
14
 
15
- Every 2 seconds Agent Lookout lists the folder `~/.claude/sessions/` and reads each file in it whose name ends in `.json`. Claude Code keeps one small file there for each running session, named `<pid>.json`. Agent Lookout reads only ordinary files of 256 KB or less, and on macOS and Linux it does not follow a link. From each file it keeps these fields and drops the rest: `pid`, `sessionId`, `cwd`, `startedAt`, `kind`, `entrypoint`, `name`, `status`, `waitingFor`, `state`, `statusUpdatedAt` and `procStart`. `entrypoint` says whether the session runs in a terminal, in VS Code or in the desktop app, `statusUpdatedAt` says when its status last changed, and `procStart` says when its process started. It makes no use of when these files were last written.
15
+ Every 2 seconds Agent Lookout lists the folder `~/.claude/sessions/` and reads each file in it whose name ends in `.json`. Claude Code keeps one small file there for each running session, named `<pid>.json`. Agent Lookout reads only ordinary files of 256 KB or less, and it does not follow a link. Windows has no way to open a file without following a link at its name, so there Agent Lookout looks at the name first, opens only an ordinary file, and reads nothing unless the file it opened is the one it looked at. Each file this page says is read without following a link is opened that way on Windows. From each file it keeps these fields and drops the rest: `pid`, `sessionId`, `cwd`, `startedAt`, `kind`, `entrypoint`, `name`, `status`, `waitingFor`, `state`, `statusUpdatedAt` and `procStart`. `entrypoint` says whether the session runs in a terminal, in VS Code or in the desktop app, `statusUpdatedAt` says when its status last changed, and `procStart` says when its process started. It makes no use of when these files were last written.
16
16
 
17
17
  ### Claude Code's transcripts
18
18
 
19
19
  Claude Code keeps each session's conversation in a transcript, `~/.claude/projects/<folder>/<session ID>.jsonl`, where the folder is named after the session's folder. Agent Lookout reads one only while its session is waiting for you, as the registry or the `claude` command says, and reads nothing of any transcript otherwise.
20
20
 
21
- For a waiting session it looks for the file in the folder named after the session's folder, and, when it is not there, in each folder in `~/.claude/projects/`, by name, which lists those folders. It uses the session ID only once it has checked that it is an ID, and opens only an ordinary file: on macOS and Linux it does not follow the transcript file when it is a link, and it never reads a named pipe or a device. The folders above the file are followed when they are links: a folder in `~/.claude/projects/` that is a link, or `projects` itself. It reads at most the last 256 KB of the file, by position, and reads it again only when the file's size or modified time has changed. While a wait goes on it does not look for a file again, except every 10 seconds when none was found.
21
+ For a waiting session it looks for the file in the folder named after the session's folder, and, when it is not there, in each folder in `~/.claude/projects/`, by name, which lists those folders. It uses the session ID only once it has checked that it is an ID, and opens only an ordinary file: it does not follow the transcript file when it is a link, and it never reads a named pipe or a device. The folders above the file are followed when they are links: a folder in `~/.claude/projects/` that is a link, or `projects` itself. It reads at most the last 256 KB of the file, by position, and reads it again only when the file's size or modified time has changed. While a wait goes on it does not look for a file again, except every 10 seconds when none was found.
22
22
 
23
23
  From those bytes it takes the last tool the session asked to use that has no answer yet, leaving out the lines of the session's subagents, and keeps one line of plain text of at most 200 characters about it, cleaned of control characters:
24
24
 
@@ -31,7 +31,7 @@ From those bytes it takes the last tool the session asked to use that has no ans
31
31
 
32
32
  Everything else in those bytes, which can include your prompts, the agent's replies, the code it wrote and the output of tools, is dropped as soon as the line is made. When nothing in the end of the file fits, there is no line, and nothing is guessed.
33
33
 
34
- That line is shown in the Needs you panel and in the session's details, is put in the notification of that wait that the dashboard page or the server shows on this machine, in the Mac app is in the menu that its icon in the menu bar opens, and is in the session list the API serves on this computer. It is kept in memory beside the place of the file and its size and modified time, only while the session waits, and is forgotten on the first poll after the wait ends. It is not written to disk, not kept in the event log or the history, and not put in an answer of `agent-lookout mcp`. It is put in an email or a webhook post only when you turn that on, as [Email](#email) and [Webhook](#webhook) say. Set `AGENT_LOOKOUT_WAITING_TEXT=off` and no transcript is opened at all, so there is no line to send either.
34
+ That line is shown in the Needs you panel and in the session's details, is put in the notification of that wait that the dashboard page or the server shows on this machine, in the Mac app is in the menu that its icon in the menu bar opens, and is in the session list the API serves on this computer. It is kept in memory beside the place of the file and its size and modified time, only while the session waits, and is forgotten on the first poll after the wait ends. It is not written to disk, not kept in the event log or the history, and not put in an answer of `agent-lookout mcp`. It is put in an email or a webhook post only when you turn that on, as [Email](#email) and [Webhook](#webhook) say. It also goes to another computer that names this one in `AGENT_LOOKOUT_REMOTES` and reads its sessions over SSH, which shows it, and whose own email and webhook settings decide whether it is sent on, as [Another machine over SSH](#another-machine-over-ssh) says. Set `AGENT_LOOKOUT_WAITING_TEXT=off` and no transcript is opened at all, so there is no line to send either.
35
35
 
36
36
  ### `claude agents --json --all`
37
37
 
@@ -41,11 +41,11 @@ From each entry it keeps these fields and drops the rest: `pid`, `cwd`, `kind`,
41
41
 
42
42
  The command is started directly, with no shell, with stdin closed and a 5 second timeout. It is not run at all when `AGENT_LOOKOUT_CLAUDE_FEED` is `off`, or when `AGENT_LOOKOUT_CLAUDE_HOME` is set and `AGENT_LOOKOUT_CLAUDE_BIN` is not.
43
43
 
44
- To find the `claude` binary, Agent Lookout reads the `PATH` environment variable and checks whether a program named `claude` exists in each `PATH` directory, then at `~/.local/bin/claude`, `/opt/homebrew/bin/claude`, `/usr/local/bin/claude`, `~/.npm-global/bin/claude` and `/usr/bin/claude`. When `AGENT_LOOKOUT_CLAUDE_BIN` is set, it checks that path and nothing else.
44
+ To find the `claude` binary, Agent Lookout reads the `PATH` environment variable and checks whether a program named `claude` exists in each `PATH` directory, then at `~/.local/bin/claude`, `/opt/homebrew/bin/claude`, `/usr/local/bin/claude`, `~/.npm-global/bin/claude` and `/usr/bin/claude`. On Windows it checks each `PATH` directory for `claude.com` and `claude.exe`, and then for `node_modules\@anthropic-ai\claude-code\bin\claude.exe` under it, where npm keeps the program that its `claude.cmd` runs, then `%USERPROFILE%\.local\bin\claude.exe` and that npm path under `%APPDATA%\npm`. It never runs a `.cmd` or a `.bat`, which only a shell can run. When `AGENT_LOOKOUT_CLAUDE_BIN` is set, it checks that path and nothing else.
45
45
 
46
46
  ### `ps`
47
47
 
48
- A registry file can outlive a crashed session, and the system can later give its process ID to another program. To catch that, Agent Lookout runs `ps -o pid=,lstart= -p <pids>`, which prints when each of those processes started, and compares the answer with the `procStart` that the registry file recorded. A file whose process started at another time is not shown as a session. One run covers several processes, and each process is asked about at most once every 30 seconds. `ps` is run directly from `/usr/bin` or `/bin`, never through a shell, and never on Windows.
48
+ A registry file can outlive a crashed session, and the system can later give its process ID to another program. To catch that, Agent Lookout runs `ps -o pid=,lstart= -p <pids>`, which prints when each of those processes started, and compares the answer with the `procStart` that the registry file recorded. A file whose process started at another time is not shown as a session. One run covers several processes, and each process is asked about at most once every 30 seconds. `ps` is run directly from `/usr/bin` or `/bin`, never through a shell, and never on Windows. On Windows, which has no `ps` and where Claude Code records no start time Agent Lookout can compare, nothing is compared: a file whose process ID has been given to another program shows as a session until that program ends.
49
49
 
50
50
  ### `tmux`
51
51
 
@@ -104,11 +104,11 @@ Nothing is done until you press Stop and then Stop session. The page then sends
104
104
  - It runs `ps -o pid=,lstart= -p <pid>` again, for that one process, and goes on only when `ps` gives the same start time the file recorded, to the second. When `ps` gives none, or one it cannot compare, nothing is done.
105
105
  - It never stops the first process, its own process, the process it was started from or any process above that, such as the Claude Code session whose terminal started it. To find those, it runs `ps -A -o pid=,ppid=`, which prints the ID of every process and of its parent, and nothing else, follows its own process up through its parents, and drops the list. It stops no process of another user's.
106
106
 
107
- Then, for a session in a terminal or in VS Code, it sends SIGTERM to that one process, by the system call, as `kill -TERM <pid>` would, and looks every 200 milliseconds, for up to 10 seconds, whether it has ended. If it is still running, the page says so. It never sends SIGKILL to a session, and it signals no other session. For a background job, it runs the `claude` binary it found for `claude agents`, as `claude stop <id>`, with the job's ID that `claude agents` gave it and nothing else, started directly, never through a shell, with stdin closed, a 10 second timeout and the same two variables as `claude agents`. If `claude stop` runs past its 10 seconds, Agent Lookout ends that command, and anything it started, with SIGTERM and then SIGKILL, as it does `claude agents` when that runs past its time: that command is Agent Lookout's own, not the session. It never signals a background job's process, which Claude Code's supervisor would start again. Once a job is stopped, it runs `claude agents --json --all` once more at the next poll, so the job shows as stopped.
107
+ Then, for a session in a terminal or in VS Code, it sends SIGTERM to that one process, by the system call, as `kill -TERM <pid>` would, and looks every 200 milliseconds, for up to 10 seconds, whether it has ended. If it is still running, the page says so. It never sends SIGKILL to a session, and it signals no other session. For a background job, it runs the `claude` binary it found for `claude agents`, as `claude stop <id>`, with the job's ID that `claude agents` gave it and nothing else, started directly, never through a shell, with stdin closed, a 10 second timeout and the same two variables as `claude agents`. If `claude stop` runs past its 10 seconds, Agent Lookout ends that command, and anything it started, with SIGTERM and then SIGKILL, as it does `claude agents` when that runs past its time: that command is Agent Lookout's own, not the session. It never signals a background job's process, which Claude Code's supervisor would start again. Once `claude stop` has answered, it looks the same way, for up to 10 seconds, whether the job's process has ended, since the supervisor can end it a moment later, and then runs `claude agents --json --all` once more at the next poll, so the job shows as stopped.
108
108
 
109
109
  The sessions left running are the Claude Code sessions that have been idle for 24 hours or more, or as long as the [idle rule](docs/GUIDE.md#time-rules) says while it is on, by their registry file's status time, whose process still runs and which can be stopped. The Sessions card says how many there are, and lists them when you press Review…. End all… lists each one again, up to 20 at a time, and ending them sends the server each session's ID and the moment its idle began, as the page showed it. The server makes every check above for each one, and also checks that its registry file, and its own latest list of sessions, still say it is idle, since that same moment, and that this was 24 hours or more ago, or as long ago as the idle rule says. A session that has done anything since is left running.
110
110
 
111
- Stopping keeps the conversation: it touches no transcript and no file under `~/.claude`, and a registry file left behind is not deleted. The Events log keeps one event for each session stopped, with its ID, its name, the status it had and that Agent Lookout stopped it, as [The history](#the-history) says. With `AGENT_LOOKOUT_STOP=off`, nothing is offered Stop, and the server answers no request to stop a session.
111
+ Stopping keeps the conversation: it touches no transcript and no file under `~/.claude`, and a registry file left behind is not deleted. The Events log keeps one event for each session stopped, with its ID, its name, the status it had and that Agent Lookout stopped it, as [The history](#the-history) says. With `AGENT_LOOKOUT_STOP=off`, nothing is offered Stop, and the server answers no request to stop a session. On Windows it is the same whatever the setting, since there is no `ps` to confirm a process's start time and no POSIX signal to send.
112
112
 
113
113
  ### Codex's files
114
114
 
@@ -133,7 +133,7 @@ A session file or `session_index.jsonl` that is a link, a named pipe or a device
133
133
 
134
134
  Any agent can write one small JSON file for each of its sessions into a folder for Agent Lookout to read, as the [guide](docs/GUIDE.md#your-own-agents) describes. The folder is `~/.agent-lookout/sessions`, or the one `AGENT_LOOKOUT_STATUS_DIR` names. Agent Lookout never makes it.
135
135
 
136
- Every 2 seconds Agent Lookout lists that folder and reads each file directly in it whose name ends in `.json` and does not start with a dot: at most 200 files. When there are more, it looks up when each was last written, without opening it, and reads the 200 written most recently. It reads only ordinary files of 16 KB or less, and on macOS and Linux it does not follow a symbolic link in the folder. The folder itself is followed when it is a link. It does not look in folders inside it. When the folder is not there, it lists nothing else.
136
+ Every 2 seconds Agent Lookout lists that folder and reads each file directly in it whose name ends in `.json` and does not start with a dot: at most 200 files. When there are more, it looks up when each was last written, without opening it, and reads the 200 written most recently. It reads only ordinary files of 16 KB or less, and it does not follow a symbolic link in the folder. The folder itself is followed when it is a link. It does not look in folders inside it. When the folder is not there, it lists nothing else.
137
137
 
138
138
  From each file it keeps these fields and drops the rest: `agent`, `name`, `cwd`, `status`, `reason`, `since`, `pid` and `app`. `agent` is the agent's name, `cwd` the folder the session works in, `since` when its status began, `pid` the ID of its process and `app` the app the session runs in. It also keeps each file's name, which tells one session from another, and the time the file was last written, taken from the file it opened, which says how long a finished session stays and how long a working session has been quiet. The Sources card names the first file it skipped, so you can find it.
139
139
 
@@ -149,7 +149,7 @@ It looks for an entry named `.git` in the session's folder, then in each folder
149
149
  - When `.git` is a file, as in a worktree or a submodule, it reads that file, which names the repository's git folder in one line, `gitdir: <path>`, then reads `HEAD` in the folder it names, and `commondir` beside it when there is one. A worktree's git folder has a `commondir`, one line naming the git folder of the repository the worktree was made from. A submodule's has none.
150
150
  - When `.git` is anything else, such as a symbolic link, it reads nothing, and the session has no branch.
151
151
 
152
- It reads only ordinary files of 4 KB or less, and on macOS and Linux it does not follow a `HEAD` or a `commondir` that is a symbolic link. `HEAD` says either the name of the branch that is checked out, which Agent Lookout keeps, cleaned of control characters and of the characters that change the direction of text, and cut to 200 characters, or the ID of a commit when no branch is, of which it keeps the first seven characters. It keeps nothing else from these files. For each session's folder it reads them at most once every 10 seconds, and it forgets a folder when no session is in it.
152
+ It reads only ordinary files of 4 KB or less, and it does not follow a `HEAD` or a `commondir` that is a symbolic link. `HEAD` says either the name of the branch that is checked out, which Agent Lookout keeps, cleaned of control characters and of the characters that change the direction of text, and cut to 200 characters, or the ID of a commit when no branch is, of which it keeps the first seven characters. It keeps nothing else from these files. For each session's folder it reads them at most once every 10 seconds, and it forgets a folder when no session is in it.
153
153
 
154
154
  With the branch it keeps which repository the folder belongs to, so the dashboard can group the worktrees of one repository together. A repository is known by its own git folder, which all its worktrees share: a `.git` folder is its own, a worktree's `commondir` names it, and any other `.git` file, such as a submodule's, names it in its one line. Agent Lookout reads nothing more for this. It keeps two things about the repository: its name, cleaned and cut as a branch is, and an id to tell repositories apart, the first 16 characters of the SHA-256 hash of the git folder's path. The name is that of the folder that holds `.git`, such as `storefront`, and for a worktree the one its repository's git folder gives: `storefront` for `storefront/.git`, `storefront/.bare` or `storefront.git`. Both are in the session list the API serves on this computer, beside the branch, and nowhere else: no email, post, notification or answer of `agent-lookout mcp` holds them. The path itself is not sent. The id is never shown, and holds no part of the path, though someone who guessed a path could check the guess against it.
155
155
 
@@ -182,25 +182,31 @@ The pull request is in the session list the API serves on this computer, and so
182
182
 
183
183
  ### `osascript`
184
184
 
185
- With notifications on, and no dashboard page open to show one, Agent Lookout shows a notification itself when a session starts waiting for you, or, if you chose those too, finishes, fails or ends. On macOS it does that by running `/usr/bin/osascript`, the program macOS provides for running AppleScript. It gives it a script that never changes, which shows a notification, and two arguments for that script: the session's name and the reason, with what the session is asking when that is known, or what happened. The name is handed over as text to be shown. It is never made part of the script, so nothing in a name can run as AppleScript or be read as an option.
185
+ With notifications on, and no dashboard page open to show one, Agent Lookout shows a notification itself when a session starts waiting for you, or, if you chose those too, finishes, fails or ends. On macOS it does that by running `/usr/bin/osascript`, the program macOS provides for running AppleScript, except in the Mac app, which shows them as its own, as [From the server](#from-the-server) says. It gives it a script that never changes, which shows a notification, and two arguments for that script: the session's name and the reason, with what the session is asking when that is known, or what happened. The name is handed over as text to be shown. It is never made part of the script, so nothing in a name can run as AppleScript or be read as an option.
186
186
 
187
187
  `osascript` is started directly, by that full path, never through a shell, with stdin closed and a 5 second timeout. It is not run on any other system, and never while notifications are off. [Terminal and iTerm2](#terminal-and-iterm2) says when it is also run for Jump. While it runs, for a fraction of a second, the name is one of that program's arguments, which other programs on this machine can read from the list of running processes. [Notifications](#notifications) says when notifications are on and what one holds.
188
188
 
189
- ### `open` and `xdg-open`
189
+ ### `open`, `xdg-open` and `rundll32.exe`
190
190
 
191
- Only when you start it with `agent-lookout --open`, Agent Lookout runs `/usr/bin/open` on macOS, or `xdg-open` on Linux, once, to open its own address in your default browser. It gives it one argument, the address it listens on, such as `http://127.0.0.1:4777`, and nothing else. The program is started directly, never through a shell, with nothing connected to its input or output. Agent Lookout waits up to 10 seconds for it to end, to tell whether it worked, and never stops it: `xdg-open` can keep running until the browser it started is closed. Without `--open`, neither is ever run.
191
+ Only when you start it with `agent-lookout --open`, Agent Lookout runs `/usr/bin/open` on macOS, `xdg-open` on Linux, or on Windows `rundll32.exe url.dll,FileProtocolHandler` from `System32` in the Windows folder, once, to open its own address in your default browser. It gives it one argument, the address it listens on, such as `http://127.0.0.1:4777`, and nothing else. The program is started directly, never through a shell, with nothing connected to its input or output. Agent Lookout waits up to 10 seconds for it to end, to tell whether it worked, and never stops it: `xdg-open` can keep running until the browser it started is closed. Without `--open`, none of them is ever run.
192
192
 
193
193
  ### The Claude Code plugin and permission prompts
194
194
 
195
195
  Agent Lookout can answer a Claude Code permission prompt only once you install its plugin in Claude Code, which you do yourself, in Claude Code, with `/plugin marketplace add Olanetsoft/agent-lookout` and `/plugin install agent-lookout@agent-lookout`. Claude Code records that in its own settings. Agent Lookout writes nothing under `~/.claude`, and `/plugin uninstall agent-lookout@agent-lookout` takes the plugin away again.
196
196
 
197
- The plugin is one hook, a short `sh` script, which Claude Code runs as it is about to ask you for permission, while it shows its own prompt. The script checks for Agent Lookout's socket, `~/.agent-lookout/answer.sock`, or the one `AGENT_LOOKOUT_ANSWER_SOCKET` names, and with none there it exits at once and prints nothing. Otherwise it runs `curl` once, which sends the request over that socket, on this computer and nowhere else, and prints the answer, if there is one. What Claude Code hands the hook, and so what the request holds, is the session's ID, the path of its transcript, its working folder, its scratchpad folder, the ID of the prompt being answered, its permission mode, the tool's name, the tool's input, which is the whole command for a shell command and the whole file for a new file, and the permission rules Claude Code suggests. Agent Lookout reads it as it arrives, keeps the session's ID, the tool's name, what it shows of the input, and whether a subagent asks, and lets the rest go at once. It takes no request larger than 1 MiB. A request is held only once the registry file of a session Agent Lookout lists says it waits for permission, which it must say within 3 seconds, so a request for any other session is let go then, answering nothing, and is never shown.
197
+ The plugin is one hook, a short `sh` script, which Claude Code runs as it is about to ask you for permission, while it shows its own prompt. The script checks for Agent Lookout's socket, `~/.agent-lookout/answer.sock`, or the one `AGENT_LOOKOUT_ANSWER_SOCKET` names, and with none there it exits at once and prints nothing. Otherwise it runs `curl` once, which sends the request over that socket, on this computer and nowhere else, and prints the answer, if there is one. On Windows Agent Lookout opens no socket, so the hook always finds none. What Claude Code hands the hook, and so what the request holds, is the session's ID, the path of its transcript, its working folder, its scratchpad folder, the ID of the prompt being answered, its permission mode, the tool's name, the tool's input, which is the whole command for a shell command and the whole file for a new file, and the permission rules Claude Code suggests. Agent Lookout reads it as it arrives, keeps the session's ID, the tool's name, what it shows of the input, and whether a subagent asks, and lets the rest go at once. It takes no request larger than 1 MiB. A request is held only once the registry file of a session Agent Lookout lists says it waits for permission, which it must say within 3 seconds, so a request for any other session is let go then, answering nothing, and is never shown.
198
198
 
199
199
  Agent Lookout listens on that socket while it runs, unless you start it with `AGENT_LOOKOUT_ANSWER=off`, or with `AGENT_LOOKOUT_CLAUDE_HOME` set and `AGENT_LOOKOUT_ANSWER_SOCKET` not. It makes the folder with mode 700 if it is not there, and gives its own folder, `~/.agent-lookout`, mode 700 if others could open it. A folder that `AGENT_LOOKOUT_ANSWER_SOCKET` names, which it did not make, it never changes: if others can open it, answering is off, and Settings says why. It gives the socket mode 600, so only your user can connect. A browser cannot reach a socket. It removes the socket when it stops, and one left by a copy that crashed is replaced. A second copy that finds the first answering there leaves it be, and its Settings say so.
200
200
 
201
201
  While the session waits, Agent Lookout holds the request. It reads the session's registry file, `~/.claude/sessions/<pid>.json`, again every half second, as an ordinary file it opens without following a link, and lets the request go, answering nothing, as soon as the file no longer says the session is waiting for permission, or says it is waiting again in a later wait, which is what happens when you answer in the session. It also lets it go when the hook's connection closes, when a newer request of the same session arrives, and after `AGENT_LOOKOUT_ANSWER_WAIT` seconds, 300 unless you set it. The prompt in the session then decides, as it would without the plugin. What it shows of the request, the whole command or the tool and its inputs, is held in memory while the request is held. It goes to the dashboard in the session list, and nowhere else: it is never written to disk and never put in an event, the history, a notification, an email, a webhook post, `agent-lookout status` or an answer of `agent-lookout mcp`.
202
202
 
203
- It answers only when you press Allow or Deny on the dashboard. The page sends the session's ID, Agent Lookout's own ID for the request, and the answer. Agent Lookout reads the registry file once more, and answers only if it still says the session is waiting for permission, in the same wait the request was shown in. The answer is one of two fixed texts, allow, or deny with a fixed sentence that says you denied it from Agent Lookout. It never changes the command or the tool's input, and never saves a permission rule, so each Allow allows that one request. Allow is offered only when the whole of what it allows is shown, and not for an edit or a new file, a plan or a question, a request too long to show whole or with more than two blank lines in a row, one with characters that cannot be shown as they are, or a command with right-to-left letters. The Events log keeps one event for each answer, with the session's ID and name, and whether it was allowed or denied, and nothing of what was asked.
203
+ It answers when you press Allow or Deny on the dashboard, or when a [permission rule](#permission-rules) you added decides. The page sends the session's ID, Agent Lookout's own ID for the request, and the answer. Agent Lookout reads the registry file once more, and answers only if it still says the session is waiting for permission, in the same wait the request was shown in. The answer is one of two fixed texts, allow, or deny with a fixed sentence that says you denied it from Agent Lookout. It never changes the command or the tool's input, and never saves a permission rule, so each Allow allows that one request. Allow is offered only when the whole of what it allows is shown, and not for an edit or a new file, a plan or a question, a request too long to show whole or with more than two blank lines in a row, one with characters that cannot be shown as they are, or a command with right-to-left letters. The Events log keeps one event for each answer, with the session's ID and name, and whether it was allowed or denied, and nothing of what was asked. Claude Code's registry file can say the session waits for a second or two after the answer, so Agent Lookout keeps the session's ID, when that wait began and when it answered, in memory only, until the file says the session has moved on or for 10 seconds at most, and takes the wait as over from the answer.
204
+
205
+ #### Permission rules
206
+
207
+ The [permission rules](docs/GUIDE.md#permission-rules) are rules you add in Settings, none until you do. A request Agent Lookout holds is put to them once the session's registry file says it waits for permission. A deny or an allow rule that decides it answers it at once, through the same path as a press, with the same checks and the same two fixed answers: it reads the registry file once more, answers only in the same wait, allows only what Allow would be offered for, and for Bash only one plain command. An ask rule, or none, leaves it held for you. The rules read only what Agent Lookout already holds of a request, the tool's name, the command and the names of the other inputs, in memory, and write none of it anywhere.
208
+
209
+ For each request a rule answers, Agent Lookout keeps the session's ID and name, the tool's name, whether it was allowed or denied, the rule as you wrote it, its tool and for Bash its command, and the time: as an event in the Events log, which the history keeps on disk with the other events, and in a list of the last 100 kept in memory for Settings, gone when Agent Lookout stops. Neither holds the command the session asked to run, or anything else of the request. The rules themselves are kept in [the settings file](#the-settings-file). With `AGENT_LOOKOUT_ANSWER=off` no rule answers anything.
204
210
 
205
211
  Settings says whether a request has reached Agent Lookout. To tell, it notes when a Claude Code session waiting for permission sent no request within 5 seconds, which is what a session without the plugin does, and keeps that time and the time of the last request, in memory only.
206
212
 
@@ -216,7 +222,7 @@ That includes what a waiting session there is asking, such as `Run: npm test`, w
216
222
 
217
223
  ### Settings
218
224
 
219
- It reads thirty-two settings from the environment: `AGENT_LOOKOUT_CLAUDE_HOME`, `AGENT_LOOKOUT_CLAUDE_BIN`, `AGENT_LOOKOUT_CLAUDE_FEED`, `AGENT_LOOKOUT_WAITING_TEXT`, `AGENT_LOOKOUT_CODEX_HOME`, `AGENT_LOOKOUT_STATUS_DIR`, `AGENT_LOOKOUT_HISTORY`, `AGENT_LOOKOUT_HISTORY_DIR`, `AGENT_LOOKOUT_SETTINGS_FILE`, `AGENT_LOOKOUT_NOTIFICATIONS`, `AGENT_LOOKOUT_TMUX`, `AGENT_LOOKOUT_TERMINAL_JUMP`, `AGENT_LOOKOUT_STOP`, `AGENT_LOOKOUT_PULL_REQUESTS`, `AGENT_LOOKOUT_ANSWER`, `AGENT_LOOKOUT_ANSWER_SOCKET`, `AGENT_LOOKOUT_ANSWER_WAIT`, `AGENT_LOOKOUT_PORT`, `AGENT_LOOKOUT_HOST`, `AGENT_LOOKOUT_REMOTES`, `AGENT_LOOKOUT_SSH_BIN`, Codex's own `CODEX_HOME`, the six email settings, `AGENT_LOOKOUT_EMAIL_TO`, `AGENT_LOOKOUT_SMTP_URL`, `AGENT_LOOKOUT_EMAIL_FROM`, `AGENT_LOOKOUT_EMAIL_AFTER`, `AGENT_LOOKOUT_EMAIL_EVENTS` and `AGENT_LOOKOUT_EMAIL_ASKING`, and the four webhook settings, `AGENT_LOOKOUT_WEBHOOK_URL`, `AGENT_LOOKOUT_WEBHOOK_EVENTS`, `AGENT_LOOKOUT_WEBHOOK_AFTER` and `AGENT_LOOKOUT_WEBHOOK_ASKING`. The `agent-lookout` command reads one more, `AGENT_LOOKOUT_URL`, the address of the Agent Lookout to ask, and `agent-lookout status` reads tmux's own `TMUX`, only to tell whether tmux is running it. `AGENT_LOOKOUT_CLAUDE_HOME` replaces `~/.claude` in everything above. [Email](#email) says how the email settings are kept, and [Webhook](#webhook) how the webhook's are. The time rules are not in the environment: Agent Lookout keeps them in a file of its own, as [The settings file](#the-settings-file) says. The [guide](docs/GUIDE.md#settings-you-can-change) says what each setting does.
225
+ It reads thirty-two settings from the environment: `AGENT_LOOKOUT_CLAUDE_HOME`, `AGENT_LOOKOUT_CLAUDE_BIN`, `AGENT_LOOKOUT_CLAUDE_FEED`, `AGENT_LOOKOUT_WAITING_TEXT`, `AGENT_LOOKOUT_CODEX_HOME`, `AGENT_LOOKOUT_STATUS_DIR`, `AGENT_LOOKOUT_HISTORY`, `AGENT_LOOKOUT_HISTORY_DIR`, `AGENT_LOOKOUT_SETTINGS_FILE`, `AGENT_LOOKOUT_NOTIFICATIONS`, `AGENT_LOOKOUT_TMUX`, `AGENT_LOOKOUT_TERMINAL_JUMP`, `AGENT_LOOKOUT_STOP`, `AGENT_LOOKOUT_PULL_REQUESTS`, `AGENT_LOOKOUT_ANSWER`, `AGENT_LOOKOUT_ANSWER_SOCKET`, `AGENT_LOOKOUT_ANSWER_WAIT`, `AGENT_LOOKOUT_PORT`, `AGENT_LOOKOUT_HOST`, `AGENT_LOOKOUT_REMOTES`, `AGENT_LOOKOUT_SSH_BIN`, Codex's own `CODEX_HOME`, the six email settings, `AGENT_LOOKOUT_EMAIL_TO`, `AGENT_LOOKOUT_SMTP_URL`, `AGENT_LOOKOUT_EMAIL_FROM`, `AGENT_LOOKOUT_EMAIL_AFTER`, `AGENT_LOOKOUT_EMAIL_EVENTS` and `AGENT_LOOKOUT_EMAIL_ASKING`, and the four webhook settings, `AGENT_LOOKOUT_WEBHOOK_URL`, `AGENT_LOOKOUT_WEBHOOK_EVENTS`, `AGENT_LOOKOUT_WEBHOOK_AFTER` and `AGENT_LOOKOUT_WEBHOOK_ASKING`. The `agent-lookout` command reads one more, `AGENT_LOOKOUT_URL`, the address of the Agent Lookout to ask, and `agent-lookout status` reads tmux's own `TMUX`, only to tell whether tmux is running it. `AGENT_LOOKOUT_CLAUDE_HOME` replaces `~/.claude` in everything above. [Email](#email) says how the email settings are kept, and [Webhook](#webhook) how the webhook's are. The time rules and the permission rules are not in the environment: Agent Lookout keeps them in a file of its own, as [The settings file](#the-settings-file) says. The [guide](docs/GUIDE.md#settings-you-can-change) says what each setting does.
220
226
 
221
227
  ## What it never reads
222
228
 
@@ -229,7 +235,7 @@ It reads thirty-two settings from the environment: `AGENT_LOOKOUT_CLAUDE_HOME`,
229
235
  - Your `~/.ssh` folder: keys, `known_hosts` and ssh config. For the machines `AGENT_LOOKOUT_REMOTES` names, `ssh` reads them itself, as it does in a terminal.
230
236
  - The files of any other application.
231
237
 
232
- It runs no program but the `claude` binary, for `claude agents` and, only when you stop a background job, `claude stop`, `ps`, `tmux`, on macOS `osascript`, to show a notification and to bring a tab of Terminal or iTerm2 forward, only for `--open`, `open` or `xdg-open`, only with `AGENT_LOOKOUT_PULL_REQUESTS=on`, `gh`, and, only for the machines `AGENT_LOOKOUT_REMOTES` names, `ssh`, as [Another machine over SSH](#another-machine-over-ssh) describes. The Mac app also runs `ditto` and `plutil` to unpack and check a newer version of itself, and, only when you press Install and Restart, a short `sh` script that puts it in place, as [Updates (Mac app only)](#updates-mac-app-only) describes. It runs no git command. The plugin's hook, which Claude Code runs and not Agent Lookout, runs `curl`. It never writes to `~/.claude`, to the Codex folder, to the folder of status files, to any git repository or to any agent tool's files, and it never sends input to a session. It never makes, renames or deletes a status file. It changes three things outside itself, and each only when you ask: which tmux pane, window and session are selected, or which tab of Terminal or iTerm2 is in front, when you press Jump, when you press Stop and confirm, whether a Claude Code session's process runs, as [Stopping a session](#stopping-a-session) describes, and, when you press Allow or Deny, the answer to that one permission prompt, as [The Claude Code plugin and permission prompts](#the-claude-code-plugin-and-permission-prompts) describes. It never sends a session anything else.
238
+ It runs no program but the `claude` binary, for `claude agents` and, only when you stop a background job, `claude stop`, `ps`, `tmux`, on macOS `osascript`, to show a notification and to bring a tab of Terminal or iTerm2 forward, only for `--open`, `open`, `xdg-open` or `rundll32.exe`, only with `AGENT_LOOKOUT_PULL_REQUESTS=on`, `gh`, and, only for the machines `AGENT_LOOKOUT_REMOTES` names, `ssh`, as [Another machine over SSH](#another-machine-over-ssh) describes. The Mac app also runs `ditto` and `plutil` to unpack and check a newer version of itself, and, only when you press Install and Restart, a short `sh` script that puts it in place, as [Updates (Mac app only)](#updates-mac-app-only) describes. It runs no git command. The plugin's hook, which Claude Code runs and not Agent Lookout, runs `curl`. It never writes to `~/.claude`, to the Codex folder, to the folder of status files, to any git repository or to any agent tool's files, and it never sends input to a session. It never makes, renames or deletes a status file. It changes three things outside itself, and each only when you ask: which tmux pane, window and session are selected, or which tab of Terminal or iTerm2 is in front, when you press Jump, when you press Stop and confirm, whether a Claude Code session's process runs, as [Stopping a session](#stopping-a-session) describes, and, when you press Allow or Deny, or a [permission rule](#permission-rules) you added decides it, the answer to that one permission prompt, as [The Claude Code plugin and permission prompts](#the-claude-code-plugin-and-permission-prompts) describes. It never sends a session anything else.
233
239
 
234
240
  ## Network
235
241
 
@@ -243,11 +249,11 @@ The `claude agents` command is Claude Code's own program, and it may contact Ant
243
249
 
244
250
  The API refuses any request whose `Host` header is not `localhost`, `127.0.0.1` or `[::1]`, any request whose `Origin` header names another site, and any request the browser marks as cross-site. It sends no CORS headers. Together these stop a website you visit from reading your session names and paths through your browser.
245
251
 
246
- Each request the dashboard makes carries one header of Agent Lookout's own, `X-Agent-Lookout-Notifications`, which says which events that page has notifications on for: `off`, `on`, which means a session starting to wait, or `on; events=` followed by the names of the events, such as `on; events=needs-you,finished`. It holds nothing else. It goes to Agent Lookout's own server and nowhere else. [Notifications](#notifications) says what the server does with it. The request the Jump button sends for a session in tmux, Terminal or iTerm2 carries one more, `X-Agent-Lookout-Action: jump`, which names what is asked for, and the request the Clear history button in Settings sends carries `X-Agent-Lookout-Action: clear-history`, with an empty body. The request Stop session sends carries `X-Agent-Lookout-Action: stop` and the session's ID, and the one that ends the sessions left running carries `X-Agent-Lookout-Action: clean-up`, with each session's ID and the moment its idle began. The one Allow and Deny send carries `X-Agent-Lookout-Action: answer`, with the session's ID, Agent Lookout's own ID for the request and the answer.
252
+ Each request the dashboard makes carries one header of Agent Lookout's own, `X-Agent-Lookout-Notifications`, which says which events that page has notifications on for: `off`, `on`, which means a session starting to wait, or `on; events=` followed by the names of the events, such as `on; events=needs-you,finished`. It holds nothing else. It goes to Agent Lookout's own server and nowhere else. [Notifications](#notifications) says what the server does with it. The request the Jump button sends for a session in tmux, Terminal or iTerm2 carries one more, `X-Agent-Lookout-Action: jump`, which names what is asked for, and the request the Clear history button in Settings sends carries `X-Agent-Lookout-Action: clear-history`, with an empty body. The request Stop session sends carries `X-Agent-Lookout-Action: stop` and the session's ID, and the one that ends the sessions left running carries `X-Agent-Lookout-Action: clean-up`, with each session's ID and the moment its idle began. The one Allow and Deny send carries `X-Agent-Lookout-Action: answer`, with the session's ID, Agent Lookout's own ID for the request and the answer. The one the Time rules card sends carries `X-Agent-Lookout-Action: time-rules`, with the three rules, and the one the Permission rules card sends carries `X-Agent-Lookout-Action: permission-rules`, with one change to the rules. In the Mac app, the Updates card also sends `X-Agent-Lookout-Action: check-for-updates` and `install-update`, each with the body `{}`, and `update-setting`, with `{"automatic": true}` or `false`. The Menu bar card sends `menu-bar-setting`, with `{"show": true}` or `false`.
247
253
 
248
- The local server has no password. While Agent Lookout is running, another program on the same machine can request the same data, and on a shared computer so can another user account. Such a program can also send that header, and so turn the notifications the server shows on or off. It can also ask the server to select a tmux pane, or bring a tab of Terminal or iTerm2 forward, as the Jump button does, to clear the history, as the Clear history button does, to stop a Claude Code session, or end the sessions left running, as Stop and End all… do, with every check of [Stopping a session](#stopping-a-session), and to answer a permission prompt Agent Lookout is holding, as Allow and Deny do. A program that can do that can already type into your terminal, but on a shared computer another account could not. The Mac app opens no port, so there only its own window can do any of this. `AGENT_LOOKOUT_STOP=off` takes stopping away, and `AGENT_LOOKOUT_ANSWER=off` takes answering away.
254
+ The local server has no password. While Agent Lookout is running, another program on the same machine can request the same data, and on a shared computer so can another user account. Such a program can also send that header, and so turn the notifications the server shows on or off. It can also ask the server to select a tmux pane, or bring a tab of Terminal or iTerm2 forward, as the Jump button does, to clear the history, as the Clear history button does, to stop a Claude Code session, or end the sessions left running, as Stop and End all… do, with every check of [Stopping a session](#stopping-a-session), to answer a permission prompt Agent Lookout is holding, as Allow and Deny do, and to change the time rules or the permission rules, as Settings does, which includes adding an allow rule that then answers prompts without a press. A program that can do that can already type into your terminal, but on a shared computer another account could not. The Mac app opens no port, so there only its own window can ask any of this. It shares the settings file, though. A program running as you can write `~/.agent-lookout/settings.json`, or start `npx agent-lookout` beside the app and ask that copy to change a rule, and the Mac app puts the time rules and permission rules the file then holds in force at its next poll, an allow rule included. `AGENT_LOOKOUT_STOP=off` takes stopping away, and `AGENT_LOOKOUT_ANSWER=off` takes answering away.
249
255
 
250
- For a session in VS Code, the Jump button opens a `vscode://` address that contains the session ID. Your operating system hands it to VS Code. For a session in tmux, the Jump button sends a request that holds the session's ID to Agent Lookout's own server, which selects the pane as described under [`tmux`](#tmux). For a session in Terminal or iTerm2 it sends the same request, and the server brings the tab forward as described under [Terminal and iTerm2](#terminal-and-iterm2). That request, the one Clear history sends, the ones Stop session and End send and the one Allow and Deny send are the only ones that change anything, and the server answers them only for a page served from this machine. [SECURITY.md](SECURITY.md) lists its checks.
256
+ For a session in VS Code, the Jump button opens a `vscode://` address that contains the session ID. Your operating system hands it to VS Code. For a session in tmux, the Jump button sends a request that holds the session's ID to Agent Lookout's own server, which selects the pane as described under [`tmux`](#tmux). For a session in Terminal or iTerm2 it sends the same request, and the server brings the tab forward as described under [Terminal and iTerm2](#terminal-and-iterm2). That request, the one Clear history sends, the ones Stop session and End send, the one Allow and Deny send and the ones the Time rules and Permission rules cards send are the seven that change anything, with the Mac app's four for its updates and its menu bar. The server refuses them from any website, though not from another program on this machine, as the paragraph above says, and the Mac app answers its four only for its own window. [SECURITY.md](SECURITY.md) lists its checks.
251
257
 
252
258
  ## Notifications
253
259
 
@@ -280,7 +286,7 @@ The local server shows notifications on this machine too. When one of the events
280
286
  - the session's name, as its title, with the machine's name for a session on another machine
281
287
  - what happened, as its text, in the same wordings, with what a waiting session is asking
282
288
 
283
- It holds none of Claude Code's own wording and no tag. As in the page's, what a session is asking can hold a command, a web address, or a file's full path when the file is outside the session's folder. No network request is involved. On any system but macOS the server shows nothing.
289
+ It holds none of Claude Code's own wording and no tag. As in the page's, what a session is asking can hold a command, a web address, or a file's full path when the file is outside the session's folder. No network request is involved. On any system but macOS the server shows nothing. In the Mac app, the server shows them as the app's own notifications instead, and runs no `osascript` for them. macOS files them under Agent Lookout, and a click on one brings the app's window forward.
284
290
 
285
291
  ### Reminders and summaries
286
292
 
@@ -292,8 +298,8 @@ While a page that has notifications on is open and asking every 2 seconds, the p
292
298
 
293
299
  A notification the server shows differs from the browser's:
294
300
 
295
- - macOS shows it as coming from Script Editor, which is how it labels whatever `osascript` shows. The browser's permission and its notification settings do not apply to it. On macOS 26.5, where this was checked in the system's log, macOS delivered it without first asking whether Script Editor may show notifications.
296
- - It holds nothing that could open the session or the dashboard. What a click on it does has not been checked.
301
+ - Outside the Mac app, macOS shows it as coming from Script Editor, which is how it labels whatever `osascript` shows. In the Mac app, macOS shows it as coming from Agent Lookout. The browser's permission and its notification settings do not apply to it. On macOS 26.5, where this was checked in the system's log, macOS delivered it without first asking whether Script Editor may show notifications.
302
+ - Outside the Mac app, it holds nothing that could open the session or the dashboard, and what a click on it does has not been checked. In the Mac app a click brings the window forward.
297
303
  - The server cannot take it down. It stays in Notification Centre after the session stops waiting, and after Agent Lookout stops, until you clear it.
298
304
 
299
305
  ## Email
@@ -330,11 +336,11 @@ It is never in the subject, and never in an email for a session that finished, f
330
336
 
331
337
  Each email goes to the one address in `AGENT_LOOKOUT_EMAIL_TO`, and to no other. It comes from the address in `AGENT_LOOKOUT_EMAIL_FROM`, or from the same address when that is not set. It goes through the mail server in `AGENT_LOOKOUT_SMTP_URL`, which then delivers it the way it delivers any email.
332
338
 
333
- For each email Agent Lookout looks up the server's name, opens a connection to it, signs in with the user name and password from `AGENT_LOOKOUT_SMTP_URL`, hands the email over and closes the connection. It greets the server as `[127.0.0.1]`, not by this computer's name. The server sees the network address the connection comes from, as any server you connect to does. The connection is encrypted with TLS: from the first byte when the address begins `smtps://`, and when it begins `smtp://`, the server must offer to switch to TLS before anything is sent, or nothing is sent. The server's certificate is always checked. Only to a mail server on this machine, at `127.0.0.1` or `localhost`, does `smtp://` go without TLS, since nothing leaves the machine on the way to it.
339
+ For each email Agent Lookout looks up the server's name, opens a connection to it, signs in with the user name and password from `AGENT_LOOKOUT_SMTP_URL`, hands the email over and closes the connection. It greets the server as `[127.0.0.1]`, not by this computer's name. The server sees the network address the connection comes from, as any server you connect to does. The connection is encrypted with TLS: from the first byte when the address begins `smtps://`, and when it begins `smtp://`, the server must offer to switch to TLS before anything is sent, or nothing is sent. The server's certificate is always checked, even when `NODE_TLS_REJECT_UNAUTHORIZED=0` is set. Only to a mail server on this machine, at `127.0.0.1` or `localhost`, does `smtp://` go without TLS, since nothing leaves the machine on the way to it.
334
340
 
335
341
  ### When
336
342
 
337
- `AGENT_LOOKOUT_EMAIL_EVENTS` names the events that are emailed, from `needs-you`, `finished`, `failed` and `ended`, and is `needs-you` alone unless you set it. An email is sent for a wait that begins after Agent Lookout started, once it has lasted the delay, which is one minute unless `AGENT_LOOKOUT_EMAIL_AFTER` says otherwise, if the session is still waiting then. A wait answered before then sends nothing, and so does a session that was already waiting when Agent Lookout started. Each wait sends one email at most. With the others set, an email is sent as soon as a session is seen to finish, fail or end, and none for a session that had already finished or failed when Agent Lookout started. An email that could not be sent is not tried again. At most 20 are sent in any hour, whatever they are for. Past that, none goes until the hour has passed. Claude Code sessions and sessions from a status file can be seen waiting; a Codex session never can, so it never sends one for a wait.
343
+ `AGENT_LOOKOUT_EMAIL_EVENTS` names the events that are emailed, from `needs-you`, `finished`, `failed` and `ended`, and is `needs-you` alone unless you set it. An email is sent for a wait that begins after Agent Lookout started, once it has lasted the delay, which is one minute unless `AGENT_LOOKOUT_EMAIL_AFTER` says otherwise, if the session is still waiting then. A wait answered before then sends nothing, and so does a session that was already waiting when Agent Lookout started. Each wait sends one email at most, apart from reminders. With the long wait reminder on, a wait is also reminded of once it has waited the rule's minutes, unless its email went only after that. That includes a wait already open when Agent Lookout started, if it had not waited that long yet. Each change to the minutes while it waits can bring one more, once it has waited the new number. With the others set, an email is sent as soon as a session is seen to finish, fail or end, and none for a session that had already finished or failed when Agent Lookout started. An email that could not be sent is not tried again. At most 20 are sent in any hour, whatever they are for. Past that, none goes until the hour has passed. Claude Code sessions and sessions from a status file can be seen waiting; a Codex session never can, so it never sends one for a wait.
338
344
 
339
345
  The button and the switches for notifications in Settings do not turn emails on or off, or choose what is emailed. To stop them, start Agent Lookout again without `AGENT_LOOKOUT_EMAIL_TO`.
340
346
 
@@ -437,7 +443,7 @@ Each post goes to the one address in `AGENT_LOOKOUT_WEBHOOK_URL`, and to no othe
437
443
 
438
444
  ### When
439
445
 
440
- `AGENT_LOOKOUT_WEBHOOK_EVENTS` names the events that are posted, from `needs-you`, `finished`, `failed` and `ended`, and is `needs-you` alone unless you set it. A post goes for a wait that begins after Agent Lookout started, once it has lasted the delay, which is one minute unless `AGENT_LOOKOUT_WEBHOOK_AFTER` says otherwise, if the session is still waiting then. A wait answered before then sends nothing, and so does a session that was already waiting when Agent Lookout started. Each wait sends one post at most. With the others set, a post goes as soon as a session is seen to finish, fail or end, and none for a session that had already finished or failed when Agent Lookout started. A post that could not be sent is not tried again. At most 20 posts are tried in any hour, whatever they are for, counted apart from emails. Past that, none goes until the hour has passed. These are the rules emails follow, and the two share one copy of them.
446
+ `AGENT_LOOKOUT_WEBHOOK_EVENTS` names the events that are posted, from `needs-you`, `finished`, `failed` and `ended`, and is `needs-you` alone unless you set it. A post goes for a wait that begins after Agent Lookout started, once it has lasted the delay, which is one minute unless `AGENT_LOOKOUT_WEBHOOK_AFTER` says otherwise, if the session is still waiting then. A wait answered before then sends nothing, and so does a session that was already waiting when Agent Lookout started. Each wait sends one post at most, apart from reminders. With the long wait reminder on, a wait is also reminded of once it has waited the rule's minutes, unless its post went only after that. That includes a wait already open when Agent Lookout started, if it had not waited that long yet. Each change to the minutes while it waits can bring one more, once it has waited the new number. With the others set, a post goes as soon as a session is seen to finish, fail or end, and none for a session that had already finished or failed when Agent Lookout started. A post that could not be sent is not tried again. At most 20 posts are tried in any hour, whatever they are for, counted apart from emails. Past that, none goes until the hour has passed. These are the rules emails follow, and the two share one copy of them.
441
447
 
442
448
  The button and the switches for notifications in Settings do not turn posts on or off, or choose what is posted. To stop them, start Agent Lookout again without `AGENT_LOOKOUT_WEBHOOK_URL`.
443
449
 
@@ -493,13 +499,13 @@ It answers the app that started it, over stdout, and nothing and nobody else. An
493
499
 
494
500
  - For each session: its ID, its name, its agent, the other machine it runs on, when it runs on one read over SSH, its status, why it waits, the name of its folder and never the rest of the path, its branch or commit, its app, when its status began, and how long its agent has written nothing. With `AGENT_LOOKOUT_PULL_REQUESTS=on`, also the number of its branch's pull request and whether its checks are failing, pending or passing, and never its title. Never what a waiting session is asking, which is read from its transcript.
495
501
  - For each session that needs you: the same, with how long it has waited, and one sentence naming each of them and any agent that could not be read.
496
- - For each source: its state, the sentence that says how it is read or what went wrong, which can name the folders Agent Lookout reads, such as `~/.claude/sessions`, and what its agent can report.
502
+ - For each source: its state, the sentence that says how it is read or what went wrong, which can name the folders Agent Lookout reads, such as `~/.claude/sessions`, and, for another machine, the SSH target you named, such as `dev@devbox.local`, and the last line ssh printed when it failed, and what its agent can report.
497
503
 
498
504
  When Agent Lookout cannot be reached, the answer is one sentence that says so, with the address it tried.
499
505
 
500
506
  ### What happens to an answer
501
507
 
502
- What the app does with an answer is up to the app. An agent's app normally hands each answer to its model, and for most agents the model runs on the vendor's servers, so the names of your sessions, their folders and their branches, and with `AGENT_LOOKOUT_PULL_REQUESTS=on` the numbers of their pull requests and whether their checks pass, can leave this computer that way, under that app's own settings and terms. Add the server only to an app you would show your session names to, and remove it from the app to stop it: for Claude Code, `claude mcp remove agent-lookout`.
508
+ What the app does with an answer is up to the app. An agent's app normally hands each answer to its model, and for most agents the model runs on the vendor's servers, so the names of your sessions, their folders and their branches, the SSH targets of the other machines you named, and with `AGENT_LOOKOUT_PULL_REQUESTS=on` the numbers of their pull requests and whether their checks pass, can leave this computer that way, under that app's own settings and terms. Add the server only to an app you would show your session names to, and remove it from the app to stop it: for Claude Code, `claude mcp remove agent-lookout`.
503
509
 
504
510
  ### What is kept
505
511
 
@@ -507,7 +513,7 @@ Nothing. Each answer is worked out from one reading of the list and is gone once
507
513
 
508
514
  ## Storage
509
515
 
510
- Agent Lookout keeps one thing about your sessions on disk: the history behind the Events log and the charts, so that they are still there after it restarts. [The history](#the-history) says what it holds, where it is, how long it is kept, how to clear it and how to turn it off. It also keeps its time rules in a file, which holds nothing about your sessions: [The settings file](#the-settings-file). Apart from those, its own code writes no files, except the Mac app's, below.
516
+ Agent Lookout keeps one thing about your sessions on disk: the history behind the Events log and the charts, so that they are still there after it restarts. [The history](#the-history) says what it holds, where it is, how long it is kept, how to clear it and how to turn it off. It also keeps its time rules and permission rules in a file, which holds nothing about your sessions: [The settings file](#the-settings-file). Apart from those, its own code writes no files, except the Mac app's, below.
511
517
 
512
518
  The latest session list is held in memory only, and is gone when Agent Lookout stops. What a waiting session is asking is in that list only while it waits, and in no event or point of history, on disk or in memory. So is a permission request held for the dashboard, which is also kept in memory only while it is held. With `AGENT_LOOKOUT_EMAIL_ASKING=on` or `AGENT_LOOKOUT_WEBHOOK_ASKING=on`, it is also in the email or post for that wait from the moment it is written until it is handed over, and nowhere else. So are the tmux panes and terminal tabs it last found, the branches and repositories it last read, with pull requests on the pull requests `gh` last gave and where each branch's is looked for, and what the dashboard pages last said about notifications.
513
519
 
@@ -517,7 +523,7 @@ The history is kept in the folder `~/.agent-lookout/history`, beside the folder
517
523
 
518
524
  It writes there what it already holds in memory for the Events log and the charts, and nothing else:
519
525
 
520
- - Each event: its ID, its time, the session's ID and name, whether the session appeared, changed status, ended, was stopped from Agent Lookout or had a permission prompt answered from it, the status it changed from and to, how serious the change was, for a session that was stopped, that Agent Lookout stopped it, and for a prompt that was answered, that Agent Lookout answered it and whether it allowed or denied it. A session's ID is its agent's own ID for it, or the name of its status file.
526
+ - Each event: its ID, its time, the session's ID and name, whether the session appeared, changed status, ended, was stopped from Agent Lookout or had a permission prompt answered from it, the status it changed from and to, how serious the change was, for a session that was stopped, that Agent Lookout stopped it, and for a prompt that was answered, that Agent Lookout answered it and whether it allowed or denied it, and, when a permission rule answered it, the tool's name and the rule as you wrote it, never the command the session asked to run. A session's ID is its agent's own ID for it, or the name of its status file.
521
527
  - Each history point, one for each poll: its time, and how many sessions were waiting on you, working, idle, and in all.
522
528
  - When Agent Lookout started writing, and when the history was cleared.
523
529
 
@@ -529,13 +535,13 @@ When more than one copy runs at once, such as the Mac app and `npx agent-lookout
529
535
 
530
536
  To clear the history, press Clear history on the History card in Settings and confirm. Agent Lookout deletes every history file this version wrote in the folder, and empties the Events log and the charts, which start again from that moment. The History card says where the files are, how much they hold and how far back they go. Deleting the folder while Agent Lookout is stopped clears it too.
531
537
 
532
- To keep nothing on disk, start Agent Lookout with `AGENT_LOOKOUT_HISTORY=off`. It then makes no folder and writes no file, and the last 1,000 events, the last six hours of history and what the Waits card counts are held in memory only and are gone when it stops.
538
+ To keep nothing on disk, start Agent Lookout with `AGENT_LOOKOUT_HISTORY=off`. It then makes no history folder and writes no history file, and the last 1,000 events, the last six hours of history and what the Waits card counts are held in memory only and are gone when it stops. While answering is on, it still makes the folder of its socket, `~/.agent-lookout` unless `AGENT_LOOKOUT_ANSWER_SOCKET` names another, with mode 700, and opens the socket there. The socket holds nothing and is removed when Agent Lookout stops, and the folder stays. Start it with `AGENT_LOOKOUT_ANSWER=off` as well to make no folder at all. A change to a rule in Settings still writes [the settings file](#the-settings-file).
533
539
 
534
540
  ### The settings file
535
541
 
536
- Agent Lookout keeps the [time rules](docs/GUIDE.md#time-rules) you set in Settings in `~/.agent-lookout/settings.json`, beside the history, or in the file `AGENT_LOOKOUT_SETTINGS_FILE` names, so they hold with no dashboard open and after a restart. It holds the three rules and nothing else of Agent Lookout's: whether each is on, the minutes before a reminder, the hours before a session is stale, and the times and days of quiet hours with the switch for the summary. It holds nothing about a session.
542
+ Agent Lookout keeps the [time rules](docs/GUIDE.md#time-rules) and the [permission rules](docs/GUIDE.md#permission-rules) you set in Settings in `~/.agent-lookout/settings.json`, beside the history, or in the file `AGENT_LOOKOUT_SETTINGS_FILE` names, so they hold with no dashboard open and after a restart. It holds those rules and nothing else of Agent Lookout's: whether each time rule is on, the minutes before a reminder, the hours before a session is stale, and the times and days of quiet hours with the switch for the summary, and each permission rule in its order, with an ID Agent Lookout gave it, its decision, its tool and, for Bash, the command you wrote. It holds nothing about a session. A command you write in a rule is in the file as you wrote it, so leave out of a rule anything you would not keep in a file.
537
543
 
538
- Agent Lookout reads it once, as it starts, and writes it only when you change a rule in Settings, through `POST /api/settings/time-rules`, which only the dashboard's own page can send. It writes the file whole: to a new file of mode 600, so only your user can read or change it, in the same folder, which then takes the old one's place, and makes the folder with mode 700 when it is not there. It neither reads nor writes through a link, at the file's name or the folder's, and reads no file larger than 64 KB. Anything else the file holds, such as a later version's settings, is written back as it was. A file it found but could not read as it started, such as one larger than 64 KB or one it may not read, it never writes over: a change is not saved until the file is mended or removed and Agent Lookout started again. Until you change a rule, nothing is written and no folder is made. To go back to every rule off, delete the file while Agent Lookout is stopped.
544
+ Agent Lookout reads it as it starts and again just before each change, and at each poll, every 2 seconds, it looks at the file's size and times to read it again when another copy of Agent Lookout, such as the Mac app beside `npx agent-lookout`, has written it. It writes it only when you change a rule in Settings, through `POST /api/settings/time-rules` or `POST /api/settings/permission-rules`, which the dashboard's page sends, and which another program on this computer can send too, as [Network](#network) says. It writes the file whole: to a new file of mode 600, so only your user can read or change it, in the same folder, which then takes the old one's place, and makes the folder with mode 700 when it is not there. It neither reads nor writes through a link, at the file's name or the folder's, and reads no file larger than 64 KB. Anything else the file holds, such as a later version's settings, is written back as it was. A file it finds but cannot read, such as one larger than 64 KB or one it may not read, it never writes over: a change is not saved until the file is mended or removed. Permission rules it cannot read whole, such as a later version's, are no rule at all: none of them answers anything, Settings says so, and they stay in the file as they were until you change a permission rule, which writes the list again with the rules Settings shows. Until you change a rule, nothing is written and no folder is made. To go back to every time rule off and no permission rule, delete the file while Agent Lookout is stopped.
539
545
 
540
546
  With notifications on, each notification holds a session's name, and for a wait what the session is asking, and the operating system keeps it in its notification list, as does the browser for one it made. [Notifications](#notifications) says what it holds and how long it stays. With email set up, each email holds a session's name and its folder's name, and with `AGENT_LOOKOUT_EMAIL_ASKING=on` the email for a wait holds what the session was asking, and the mail server and the mailbox keep it, as [Email](#email) says. With a webhook set up, each post holds the same, with `AGENT_LOOKOUT_WEBHOOK_ASKING=on` for what a session was asking, and the service it went to keeps it, as [Webhook](#webhook) says.
541
547
 
@@ -557,7 +563,7 @@ Session names, folder paths, repository names, branch names, pull request titles
557
563
 
558
564
  Resume puts a session's folder path and its ID on the clipboard, and only when you press it. From there, anything that reads your clipboard can see them, such as a clipboard manager, and on a Mac with Handoff on, Universal Clipboard makes them available on your other Apple devices. The page never reads the clipboard.
559
565
 
560
- With notifications on, a session's name, and what a waiting session is asking, also appear in a system notification, outside the dashboard: over other apps, in Notification Centre and, depending on your system's settings, on the lock screen and while you mirror, share or record the screen. One the dashboard page made for a wait stays there until the session stops waiting or you clear it, and one that says Finished, Failed or Ended stays until you clear it. One the server showed stays until you clear it. To keep names off those, open Notifications in System Settings on macOS and change what your browser's notifications may show, which does not cover the ones the server shows, or leave notifications off. In the Mac app, the number of sessions that need you is shown in the menu bar, beside its icon, and the menu it opens lists their names and what each is asking, with the agent, project, branch or app of two that share a name. Both show while you share or record the screen. To keep them off the menu bar, set Show in menu bar to Off in Settings. An email shows the same name, and the folder's, wherever that mailbox is read, including the notifications a phone shows for it, and so does what a waiting session is asking, with `AGENT_LOOKOUT_EMAIL_ASKING=on`. A webhook post shows them to everyone who can read the channel it goes to, and in the notifications their apps show for it, and with `AGENT_LOOKOUT_WEBHOOK_ASKING=on` shows what a waiting session is asking there too.
566
+ With notifications on, a session's name, and what a waiting session is asking, also appear in a system notification, outside the dashboard: over other apps, in Notification Centre and, depending on your system's settings, on the lock screen and while you mirror, share or record the screen. One the dashboard page made for a wait stays there until the session stops waiting or you clear it, and one that says Finished, Failed or Ended stays until you clear it. One the server showed stays until you clear it. To keep names off those, open Notifications in System Settings on macOS and change what your browser's notifications may show, which does not cover the ones the server shows (in the Mac app, both kinds come from Agent Lookout, so change Agent Lookout's own entry there), or leave notifications off. In the Mac app, the number of sessions that need you is shown in the menu bar, beside its icon, and the menu it opens lists their names and what each is asking, with the agent, project, branch or app of two that share a name. Both show while you share or record the screen. To keep them off the menu bar, set Show in menu bar to Off in Settings. An email shows the same name, and the folder's, wherever that mailbox is read, including the notifications a phone shows for it, and so does what a waiting session is asking, with `AGENT_LOOKOUT_EMAIL_ASKING=on`. A webhook post shows them to everyone who can read the channel it goes to, and in the notifications their apps show for it, and with `AGENT_LOOKOUT_WEBHOOK_ASKING=on` shows what a waiting session is asking there too.
561
567
 
562
568
  ## Changes
563
569
 
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Agent Lookout
2
2
 
3
- Agent Lookout shows the AI agent sessions on your Mac or Linux computer in one browser page, and which need you.
3
+ Agent Lookout shows the AI agent sessions on your Mac, Linux or Windows computer in one browser page, and which need you.
4
4
 
5
- It finds Claude Code and Codex sessions with no setup, and the sessions of any other agent that writes a small status file. It never starts a session. It stops one only when you press Stop and confirm, and answers a Claude Code permission prompt only when you press Allow or Deny, with its Claude Code plugin installed: it never acts on its own. By default Agent Lookout itself sends nothing anywhere. Start it with `npx agent-lookout`, or download the [Mac app](#mac-app).
5
+ It finds Claude Code and Codex sessions with no setup, and the sessions of any other agent that writes a small status file. It never starts a session. It stops one only when you press Stop and confirm, and answers a Claude Code permission prompt only when you press Allow or Deny, or by a permission rule you set, with its Claude Code plugin installed: it never acts on its own. By default Agent Lookout itself sends nothing anywhere. Start it with `npx agent-lookout`, or download the [Mac app](#mac-app).
6
6
 
7
7
  [Install](#install) · [Guide](docs/GUIDE.md) · [Privacy](#privacy) · [Roadmap](https://github.com/Olanetsoft/agent-lookout/milestones) · [Website](https://agent-lookout.vercel.app)
8
8
 
@@ -13,21 +13,22 @@ It finds Claude Code and Codex sessions with no setup, and the sessions of any o
13
13
 
14
14
  ## What it does
15
15
 
16
- | Part | Description |
17
- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18
- | [Needs you](docs/GUIDE.md#needs-you) | Lists the sessions waiting for permission or for an answer, longest wait first, each with a timer. For Claude Code it also says what the session is asking, such as `Run: npm test`. |
19
- | [Sessions](docs/GUIDE.md#sessions) | Lists the other sessions by status, by repository or on a board, each with its folder and git branch. Click one to see its details. |
20
- | [Jump](docs/GUIDE.md#jump) | Takes you to a Claude Code session. It opens it in VS Code, selects its tmux pane, or on a Mac brings its Terminal or iTerm2 tab to the front. |
21
- | [Stop](docs/GUIDE.md#stop-a-session) | Ends a Claude Code session's process when you press Stop in its details and confirm. The conversation is kept. Sessions left running, idle for a day or more, can be ended together after a confirmation. |
22
- | [Resume](docs/GUIDE.md#resume-a-session) | Copies the command that continues a Claude Code session that has ended, `cd` to its folder and `claude --resume` with its ID, for you to run in a terminal. It runs nothing itself. |
23
- | [Allow and Deny](docs/GUIDE.md#answer-a-permission-prompt) | Answers a Claude Code permission prompt from the dashboard, with the Agent Lookout plugin installed in Claude Code. It shows the whole command first, and the prompt in the session still works. |
24
- | [Notifications](docs/GUIDE.md#notifications) | Tell you when a session starts waiting and, if you choose, when one finishes, fails or ends. Off until you turn them on. On a Mac they keep coming after you close the tab, once a page with them on has been open. |
25
- | [Time rules](docs/GUIDE.md#time-rules) | Remind you of a long wait, set how long a session is idle before it is stale, and hold everything back during quiet hours, with one summary when they end. Off until you turn them on. |
26
- | [Pull requests](docs/GUIDE.md#pull-requests) | Shows a session's pull request on github.com and its checks, through your own `gh`, and marks a branch whose checks are failing. Off until you turn it on. |
27
- | [Email](docs/GUIDE.md#email) and [webhook](docs/GUIDE.md#webhook) | Send the same events to one email address, or to one webhook such as a Slack channel's, for when you are away. Off until you set them up. |
28
- | [`agent-lookout status`](docs/GUIDE.md#in-the-terminal) | Prints which sessions need you, for a terminal, a tmux status line or a script. |
29
- | [`agent-lookout mcp`](docs/GUIDE.md#for-your-agents) | Lets an AI agent ask which sessions need you. Its tools only read. |
30
- | [Status files](docs/GUIDE.md#your-own-agents) | Show any other agent, including one you wrote, when it writes one small JSON file for each session. |
16
+ | Part | Description |
17
+ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18
+ | [Needs you](docs/GUIDE.md#needs-you) | Lists the sessions waiting for permission or for an answer, longest wait first, each with a timer. For Claude Code it also says what the session is asking, such as `Run: npm test`. |
19
+ | [Sessions](docs/GUIDE.md#sessions) | Lists the other sessions by status, by repository or on a board, each with its folder and git branch. Click one to see its details. |
20
+ | [Jump](docs/GUIDE.md#jump) | Takes you to a Claude Code session. It opens it in VS Code, selects its tmux pane, or on a Mac brings its Terminal or iTerm2 tab to the front. |
21
+ | [Stop](docs/GUIDE.md#stop-a-session) | Ends a Claude Code session's process when you press Stop in its details and confirm. The conversation is kept. Sessions left running, idle for a day or more, can be ended together after a confirmation. |
22
+ | [Resume](docs/GUIDE.md#resume-a-session) | Copies the command that continues a Claude Code session that has ended, `cd` to its folder and `claude --resume` with its ID, for you to run in a terminal. It runs nothing itself. |
23
+ | [Allow and Deny](docs/GUIDE.md#answer-a-permission-prompt) | Answers a Claude Code permission prompt from the dashboard, with the Agent Lookout plugin installed in Claude Code. It shows the whole command first, and the prompt in the session still works. |
24
+ | [Permission rules](docs/GUIDE.md#permission-rules) | Decide once how a Claude Code permission prompt is answered: always allow, always ask or always deny, by tool and, for Bash, by command, such as `npm test:*`. An allow rule answers only one plain command you could allow by hand, and never one that begins with `sudo`, `env`, `sh`, `bash` or another program on [the list](docs/GUIDE.md#permission-rules) that runs a command. A rule for a package manager names its subcommand, such as `npm test:*`, and a prefix trusts every word after it. The Events log records each answer. None until you add one. |
25
+ | [Notifications](docs/GUIDE.md#notifications) | Tell you when a session starts waiting and, if you choose, when one finishes, fails or ends. Off until you turn them on. On a Mac they keep coming after you close the tab, once a page with them on has been open. |
26
+ | [Time rules](docs/GUIDE.md#time-rules) | Remind you of a long wait, set how long a session is idle before it is stale, and hold everything back during quiet hours, with one summary when they end. Off until you turn them on. |
27
+ | [Pull requests](docs/GUIDE.md#pull-requests) | Shows a session's pull request on github.com and its checks, through your own `gh`, and marks a branch whose checks are failing. Off until you turn it on. |
28
+ | [Email](docs/GUIDE.md#email) and [webhook](docs/GUIDE.md#webhook) | Send the same events to one email address, or to one webhook such as a Slack channel's, for when you are away. Off until you set them up. |
29
+ | [`agent-lookout status`](docs/GUIDE.md#in-the-terminal) | Prints which sessions need you, for a terminal, a tmux status line or a script. |
30
+ | [`agent-lookout mcp`](docs/GUIDE.md#for-your-agents) | Lets an AI agent ask which sessions need you. Its tools only read. |
31
+ | [Status files](docs/GUIDE.md#your-own-agents) | Show any other agent, including one you wrote, when it writes one small JSON file for each session. |
31
32
 
32
33
  The Overview also has a chart of the last hour, a log of events, a timeline, and how long sessions waited on you today and over the last 7 days, day by day, with the sessions that waited longest. What they show is kept on this computer for 8 days, so a restart does not empty them. Press `/` to search every session. Sources says what Agent Lookout reads for each agent. [The screen](docs/GUIDE.md#the-screen) covers each part.
33
34
 
@@ -43,7 +44,7 @@ Claude Code sessions are found whether they run in a terminal, in VS Code or in
43
44
 
44
45
  A Codex session never shows as needing you. Codex's files do not record when it is waiting for your approval, so one that is waiting for you shows as working. Once it has written nothing for 5 minutes, its row says how long it has been quiet, which is the sign to look. Codex support has been checked with the Codex desktop app, and not yet with the Codex CLI or its IDE extension. [What each agent can report](docs/GUIDE.md#what-each-agent-can-report) has the full table.
45
46
 
46
- Agent Lookout is developed and tested on macOS. On Linux, CI runs every test on Ubuntu and starts the app there, but no one has used it on a Linux desktop yet. Two things are macOS only: notifications with no dashboard tab open, and Jump to a Terminal or iTerm2 tab. [On Linux](docs/GUIDE.md#on-linux) has the rest. Windows is untested.
47
+ Agent Lookout is developed and tested on macOS. On Linux, CI runs every test and starts the app there. On Windows, it runs the tests, less those of what Windows does not have, such as POSIX signals and Unix sockets, and starts the app there. No one has used it on a Linux or Windows desktop yet. Two things are macOS only: notifications with no dashboard tab open, and Jump to a Terminal or iTerm2 tab. On Windows, Stop, Allow and Deny, the permission rules, Resume and Jump to a tmux pane are not there either. [On Linux](docs/GUIDE.md#on-linux) and [On Windows](docs/GUIDE.md#on-windows) have the rest.
47
48
 
48
49
  ## Install
49
50
 
@@ -101,7 +102,7 @@ Kept in Applications, it updates itself: about once a day it asks GitHub whether
101
102
 
102
103
  If a step prints something else, [When something goes wrong](docs/GUIDE.md#when-something-goes-wrong) says what to do for the common problems.
103
104
 
104
- To stop it, press Ctrl+C in its terminal. If it runs in the background, `lsof -nP -iTCP:4777 -sTCP:LISTEN` shows its process ID under `PID`, on macOS or on Linux with `lsof` installed. Put your port in place of 4777 if you chose another. `kill` followed by that number stops it.
105
+ To stop it, press Ctrl+C in its terminal. If it runs in the background, `lsof -nP -iTCP:4777 -sTCP:LISTEN` shows its process ID under `PID`, on macOS or on Linux with `lsof` installed. Put your port in place of 4777 if you chose another. `kill` followed by that number stops it. On Windows, `netstat -ano | findstr :4777` shows the process ID in its last column, and `taskkill /F /PID` followed by that number stops it.
105
106
 
106
107
  To start it again, run `npx agent-lookout`. `npx agent-lookout --open` also opens the page in your browser, and `--port` chooses another port. [Start it with one command](docs/GUIDE.md#start-it-with-one-command) has the options.
107
108
 
@@ -196,7 +197,7 @@ AGENT_LOOKOUT_CLAUDE_FEED=off npx agent-lookout
196
197
  | `AGENT_LOOKOUT_WAITING_TEXT=off` | Never opens a Claude Code transcript. A waiting session shows its reason alone, here and on another machine read over SSH. |
197
198
  | `AGENT_LOOKOUT_HISTORY=off` | Keeps the Events log and the charts in memory only, so they start empty each time. Nothing is written to `~/.agent-lookout/history`. |
198
199
  | `AGENT_LOOKOUT_STOP=off` | Takes away Stop and the ending of sessions left running. No session is ever stopped from Agent Lookout. |
199
- | `AGENT_LOOKOUT_ANSWER=off` | Takes away Allow and Deny. No socket is opened for the plugin, and no permission prompt is answered from Agent Lookout. |
200
+ | `AGENT_LOOKOUT_ANSWER=off` | Takes away Allow and Deny and the permission rules. No socket is opened for the plugin, and no permission prompt is answered from Agent Lookout. |
200
201
 
201
202
  [The guide](docs/GUIDE.md#settings-you-can-change) lists every setting, those for [email](docs/GUIDE.md#email) and the [webhook](docs/GUIDE.md#webhook) among them. The theme and the page's notifications are in the dashboard's Settings view.
202
203
 
@@ -208,21 +209,21 @@ By default Agent Lookout itself sends nothing anywhere: no telemetry, no analyti
208
209
  - Email and the webhook are off until you set them up. Then each goes only to the one address you name, and email goes through the mail server you name. A message holds the session's name, what happened and when, how long a wait has lasted, and the names of its folder, app and agent. It holds no path and no prompt, unless you also turn on what a waiting session is asking, below.
209
210
  - Started with `npx agent-lookout`, npm contacts its registry: to download the package the first time, and each time after to ask whether a newer version is out. That is npm's own traffic, not Agent Lookout's. Installed with `npm install -g agent-lookout` and started as `agent-lookout`, npm is not involved.
210
211
  - It runs Claude Code's own `claude agents` command, which may contact Anthropic the way Claude Code normally does. `AGENT_LOOKOUT_CLAUDE_FEED=off` stops it running that command.
211
- - While a Claude Code session waits for you, it reads the end of its transcript to show what it asks, such as `Run: npm test`. It forgets that line when the wait ends. The line stays on this machine unless you start Agent Lookout with `AGENT_LOOKOUT_EMAIL_ASKING=on` or `AGENT_LOOKOUT_WEBHOOK_ASKING=on`, which put it in the email or post for that wait. It can hold a command, a web address or a file's full path. No answer of `agent-lookout mcp` holds it. `AGENT_LOOKOUT_WAITING_TEXT=off` turns it off.
212
+ - While a Claude Code session waits for you, it reads the end of its transcript to show what it asks, such as `Run: npm test`. It forgets that line when the wait ends. The line stays on this machine unless you start Agent Lookout with `AGENT_LOOKOUT_EMAIL_ASKING=on` or `AGENT_LOOKOUT_WEBHOOK_ASKING=on`, which put it in the email or post for that wait, or another computer names this one in `AGENT_LOOKOUT_REMOTES` and reads its sessions over SSH. It can hold a command, a web address or a file's full path. No answer of `agent-lookout mcp` holds it. `AGENT_LOOKOUT_WAITING_TEXT=off` turns it off.
212
213
  - Codex's session files hold your conversations. Agent Lookout reads them for when each turn started and ended, and for a few details such as the session's folder. It keeps none of your prompts, Codex's replies or the commands Codex ran.
213
- - With the [Agent Lookout plugin](docs/GUIDE.md#answer-a-permission-prompt) installed in Claude Code, each permission request, the tool and its input, which for a new file is the whole file, goes from Claude Code to Agent Lookout over a socket in `~/.agent-lookout` that only you can open. Agent Lookout keeps what it shows of it in memory until the prompt is answered, and never writes it down or sends it on.
214
+ - With the [Agent Lookout plugin](docs/GUIDE.md#answer-a-permission-prompt) installed in Claude Code, each permission request, the tool and its input, which for a new file is the whole file, goes from Claude Code to Agent Lookout over a socket in `~/.agent-lookout` that only you can open. Agent Lookout keeps what it shows of it in memory until the prompt is answered, and never writes it down or sends it on. The [permission rules](docs/GUIDE.md#permission-rules) you add are kept in `~/.agent-lookout/settings.json`, and the Events log keeps, for each request a rule answered, the tool and the rule, never the command.
214
215
  - `agent-lookout mcp` does nothing until you add it to an agent's app. That app usually hands its answers, with your session names, folders and branches, to its model, which for most agents runs on the vendor's servers. [The MCP server](PRIVACY.md#the-mcp-server) says what an answer holds.
215
216
  - Other machines are read only once you name them in `AGENT_LOOKOUT_REMOTES`. Then it runs your own `ssh` to each, which signs in with your config and agent, and asks the Agent Lookout running there for its sessions, sending nothing of this computer's. While it is connected, other programs and user accounts on this computer can reach Agent Lookout there through its tunnel, as they can reach it here. [Another machine over SSH](PRIVACY.md#another-machine-over-ssh) says what is read.
216
217
  - Jump to a Terminal or iTerm2 tab needs macOS to let the program you start Agent Lookout from control that app. macOS asks once, and what you allow covers anything else you run from that program. Choose Don't Allow and only that Jump stops working. `AGENT_LOOKOUT_TERMINAL_JUMP=off` turns it off.
217
218
 
218
- It listens on a loopback address only, `127.0.0.1`, or `::1` if you set `AGENT_LOOKOUT_HOST`, and refuses any other, so other computers cannot reach it. It turns away requests from websites open in your browser. It has no password. While it runs, other programs and other user accounts on this computer can read it. They can also turn the notifications it shows on or off, change the time rules, do what the Jump button does, clear the history, stop a Claude Code session as the Stop button does, and answer a permission prompt it is holding as Allow and Deny do. The Mac app opens no port, so there only its own window can. It writes to no agent's files. It changes three things outside itself, and only when you ask. When you press Jump, it brings a tmux pane, or a Terminal or iTerm2 tab, to the front. When you press Stop and confirm, it ends that Claude Code session's process. When you press Allow or Deny, it answers that one permission prompt, and rewrites nothing and saves no rule. `AGENT_LOOKOUT_STOP=off` takes Stop away, and `AGENT_LOOKOUT_ANSWER=off` takes Allow and Deny away.
219
+ It listens on a loopback address only, `127.0.0.1`, or `::1` if you set `AGENT_LOOKOUT_HOST`, and refuses any other, so other computers cannot reach it. It turns away requests from websites open in your browser. It has no password. While it runs, other programs and other user accounts on this computer can read it. They can also turn the notifications it shows on or off, change the time rules and the permission rules, do what the Jump button does, clear the history, stop a Claude Code session as the Stop button does, and answer a permission prompt it is holding as Allow and Deny do. The Mac app opens no port, so there only its own window can. A program running as you can still change its rules, by writing `~/.agent-lookout/settings.json`, which the app takes up at its next poll. It writes to no agent's files. It changes three things outside itself, and only when you ask. When you press Jump, it brings a tmux pane, or a Terminal or iTerm2 tab, to the front. When you press Stop and confirm, it ends that Claude Code session's process. When you press Allow or Deny, or a permission rule you added matches, it answers that one permission prompt, and rewrites nothing and saves no rule in Claude Code. `AGENT_LOOKOUT_STOP=off` takes Stop away, and `AGENT_LOOKOUT_ANSWER=off` takes Allow, Deny and the permission rules away.
219
220
 
220
221
  ## What it does not do yet
221
222
 
222
- - It does not resume a session itself: Resume copies the command that does, for a Claude Code session that has ended. It cannot send a session a message. It stops a Claude Code session only when you press Stop and confirm, and not one in the desktop app. It answers a permission prompt only with the plugin installed, and offers Deny alone for an edit, since it does not show the change, for a plan or a question, and for a request it cannot show whole and as it is. An agent using `agent-lookout mcp` can do none of these.
223
+ - It does not resume a session itself: Resume copies the command that does, for a Claude Code session that has ended, on macOS and Linux. It cannot send a session a message. It stops a Claude Code session only when you press Stop and confirm, and not one in the desktop app or on Windows. It answers a permission prompt only with the plugin installed, and not on Windows, and offers Deny alone for an edit, since it does not show the change, for a plan or a question, and for a request it cannot show whole and as it is. A permission rule answers Claude Code's prompts only, and an allow rule never allows what you could not allow by hand, or a Bash line of more than one plain command. An agent using `agent-lookout mcp` can do none of these.
223
224
  - It shows sessions on this computer, and on [another machine](docs/GUIDE.md#another-machine-over-ssh) running Agent Lookout that you reach over SSH. Cloud sessions, Codex cloud tasks and chats in a browser tab do not appear.
224
225
  - Claude Code's session files and Codex's files are not documented by their makers. An update to either can make Agent Lookout show less, or nothing, until it is updated. [docs/adapters/codex.md](docs/adapters/codex.md#what-breaks-when-codex-changes) lists what breaks when Codex changes.
225
- - The Mac app is not signed with an Apple Developer ID yet, so the first time it is opened, macOS does not open it until you allow it in Privacy & Security. There is no app for Linux. Support for more agents is planned in the [milestones](https://github.com/Olanetsoft/agent-lookout/milestones).
226
+ - The Mac app is not signed with an Apple Developer ID yet, so the first time it is opened, macOS does not open it until you allow it in Privacy & Security. There is no app for Linux or Windows. Support for more agents is planned in the [milestones](https://github.com/Olanetsoft/agent-lookout/milestones).
226
227
 
227
228
  [What it does not do yet](docs/GUIDE.md#what-it-does-not-do-yet) has the details.
228
229