agent-lookout 0.2.3 → 0.2.4
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 +18 -0
- package/PRIVACY.md +59 -15
- package/README.md +10 -6
- package/SECURITY.md +16 -6
- package/dist/THIRD-PARTY-LICENSES.md +195 -0
- package/dist/assets/{HistoryPanel-DMnhIoFB.js → HistoryPanel-CIjshvhu.js} +1 -1
- package/dist/assets/SessionPanel-eBOdTLD9.js +1 -0
- package/dist/assets/index-B-myfVQS.js +2 -0
- package/dist/assets/index-Cceyz9yZ.css +1 -0
- package/dist/assets/radix-BH0JH8UU.js +41 -0
- package/dist/cli/agent-lookout.js +4 -4
- package/dist/cli/{chunk-GOX5UB5L.js → chunk-63XPRBHW.js} +85 -3
- package/dist/cli/{chunk-54ODUY75.js → chunk-KNOLJ3IC.js} +1 -1
- package/dist/cli/{chunk-4C34YX6S.js → chunk-XVXSGVEW.js} +6 -2
- package/dist/cli/mcpServer-HGH6PY4W.js +23664 -0
- package/dist/cli/{startCommand-H6O35VYR.js → startCommand-KNXMVM2U.js} +3996 -2822
- package/dist/index.html +3 -3
- package/docs/API.md +169 -62
- package/docs/GUIDE.md +127 -58
- package/package.json +5 -5
- package/dist/assets/SessionPanel-BNm9wCzf.js +0 -1
- package/dist/assets/atkinson-hyperlegible-mono-latin-400-normal-Cmjm2dBj.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-500-normal-BV5ipwqM.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-600-normal-CuPF9o0F.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-ext-400-normal-ITMuFrSK.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-ext-500-normal-BiHEOgiK.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-mono-latin-ext-600-normal-ZiH-ObRk.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-400-normal-DPp7N0cD.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-500-normal-B0CYqHl3.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-600-normal-BhgCag5w.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-ext-400-normal-qxMiU51n.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-ext-500-normal-oZS3KxrF.woff +0 -0
- package/dist/assets/atkinson-hyperlegible-next-latin-ext-600-normal-BBAQIogt.woff +0 -0
- package/dist/assets/index-Ckda8OV4.js +0 -2
- package/dist/assets/index-DFR77qn5.css +0 -1
- package/dist/assets/radix-27o0jeIu.js +0 -41
- package/dist/cli/mcpServer-QQFQR6DC.js +0 -246
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
Changes that a user of Agent Lookout would notice, newest first.
|
|
4
4
|
|
|
5
|
+
## 0.2.4 - 2026-10-06
|
|
6
|
+
|
|
7
|
+
Stop a Claude Code session from its details and end the ones left running, see the pull request and checks for a session's branch, and install a much smaller package with npx.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- A session's pull request on github.com, and how its checks stand, can be shown. Start Agent Lookout with `AGENT_LOOKOUT_PULL_REQUESTS=on` and it asks your own GitHub CLI, `gh`, with the login `gh` already has, so Agent Lookout never sees a token. A session's details then have a Pull request fact: its number and title, as a link that opens it on github.com in your browser, and whether it is open, a draft, merged or closed, with how many checks are failing, pending and passing. In the Sessions list and on the board, a branch whose open pull request has a failing check has a small cross after it, which says which pull request on hover or Tab. It asks only about a branch of a repository whose remote is on github.com, read from the repository's own `config`, never about the default branch or a branch named with digits alone, such as `51`, which `gh` would take for a pull request's number, and at most once every 2 minutes for each repository and branch. With it on, `gh` sends GitHub the repository's owner and name and the branch's name. Without `gh`, or with `gh` not signed in, the Pull requests card in Settings says so and nothing else changes. `agent-lookout mcp` and `agent-lookout status --json` give a branch's pull request as its number and the state of its checks, and only with the setting on. It is off by default, and any value but `on` or `off` leaves it off with one line at start that names the setting. [Pull requests](docs/GUIDE.md#pull-requests) has the details.
|
|
12
|
+
- Stop a Claude Code session from its details. Stop asks first, naming the session, saying what it does and how to open the conversation again with `claude --resume`, with focus on Cancel. Once you confirm, Agent Lookout reads the session's file in `~/.claude/sessions` and asks `ps` again, and acts only when both say the process is that session: a session in a terminal or VS Code is sent SIGTERM, never SIGKILL, and one still running 10 seconds later is said to be, and a background job is stopped with `claude stop`. The Events log records each stop. A session in Claude Code's desktop app has no Stop, and its details say to stop it there. Codex sessions and sessions from status files have none either. [Stop a session](docs/GUIDE.md#stop-a-session) has the details.
|
|
13
|
+
- Left running, a band over the Sessions list and the board, counts the Claude Code sessions idle for a day or more whose process still runs, as after a VS Code tab is closed. Review… lists each with how long it has been idle. Hide until it changes hides one in this browser. End all… lists each one with a tick and ends those you keep ticked, up to 20 at a time, and a session that has done anything since the list was drawn is left running.
|
|
14
|
+
- `AGENT_LOOKOUT_STOP=off` takes Stop and the ending of sessions left running away.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- `npx agent-lookout` installs about 4 MB, down from about 30 MB, and downloads under 2 MB. The parts of the MCP SDK and zod that `agent-lookout mcp` uses are now inside the package, so neither is installed, nor are the web servers that came with the SDK, and `mcp` works as before. The one package it installs besides itself is nodemailer, for email.
|
|
19
|
+
- The dashboard's fonts are `.woff2` files only. Every browser the dashboard supports reads them, so the `.woff` copies, which none of them downloaded, are no longer in the package.
|
|
20
|
+
- Agent Lookout no longer only watches: it stops a session when you press Stop and confirm, and never on its own. It still never starts or answers one. What each agent can report, in Sources, has a Stop column.
|
|
21
|
+
|
|
5
22
|
## 0.2.3 - 2026-10-06
|
|
6
23
|
|
|
7
24
|
The Mac app shows waiting sessions in the menu bar, the Overview says how long sessions waited on you today and over seven days, email and the webhook can carry what a waiting session is asking, new versions on npm come with provenance, and Node.js 22.12 is now the minimum.
|
|
@@ -14,6 +31,7 @@ The Mac app shows waiting sessions in the menu bar, the Overview says how long s
|
|
|
14
31
|
|
|
15
32
|
### Changed
|
|
16
33
|
|
|
34
|
+
- The dashboard leaves out an event of a kind it does not know, where it showed one as a change of status.
|
|
17
35
|
- Agent Lookout needs Node.js 22.12 or newer. Node.js 20 reached the end of its life on 30 April 2026 and no longer gets security fixes, so it is no longer supported. On an older Node, `npx agent-lookout` and `agent-lookout` stop at once with one line that names the version needed and the version found, and exit with 1, or with 2 for `agent-lookout status`. The Mac app needs no Node.js.
|
|
18
36
|
- The Overview has a Waits card that says how long sessions waited on you today and over the last 7 days, with a bar for each day and the five sessions that waited longest, today or over the 7 days, with how many times each waited. It is worked out on this computer from the history Agent Lookout keeps, counts only the time Agent Lookout was running, and says how much of each day and of the 7 days that was. With `AGENT_LOOKOUT_HISTORY=off` it covers only the time since Agent Lookout started, and says so. `GET /api/waits` gives the same totals to a program on this computer.
|
|
19
37
|
|
package/PRIVACY.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Privacy
|
|
2
2
|
|
|
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. 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.
|
|
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. 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
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.
|
|
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 never stops a session on its own, and it never answers one. [Stopping a session](#stopping-a-session) says what it checks first and what it runs.
|
|
10
|
+
|
|
9
11
|
## What it reads and runs
|
|
10
12
|
|
|
11
13
|
### Claude Code's session registry
|
|
@@ -92,6 +94,22 @@ macOS asks you once whether the program Agent Lookout runs in may control the ap
|
|
|
92
94
|
|
|
93
95
|
Agent Lookout asks the operating system whether each Claude Code session's process still exists with a signal-0 check on the process ID, which sends nothing to the process. It does the same for each status file that names a process.
|
|
94
96
|
|
|
97
|
+
### Stopping a session
|
|
98
|
+
|
|
99
|
+
A Claude Code session in a terminal or in VS Code, and a Claude Code background job, has a Stop button in its details, when its registry file names its kind, `interactive` or `bg`, and records its process's start time. A session in Claude Code's desktop app has none, since that app looks after its own processes, and nor does a session whose kind or app is not known, a Codex session or a session from a status file. A background job has one only while Agent Lookout may run the `claude` command, as [`claude agents --json --all`](#claude-agents---json---all) says. The dashboard is told only that a session can be stopped, and whether by a signal or by `claude stop`: the process ID it already shows, the start time and the job's ID stay in the server, in memory.
|
|
100
|
+
|
|
101
|
+
Nothing is done until you press Stop and then Stop session. The page then sends the server the session's ID and nothing else, and the server makes every check again at that moment, remembering nothing from before:
|
|
102
|
+
|
|
103
|
+
- It reads the session's registry file, `~/.claude/sessions/<pid>.json`, again, as an ordinary file of 256 KB or less, following no link. It must still name that session and that process, be of the same kind, and record the same start time.
|
|
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
|
+
- 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
|
+
|
|
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.
|
|
108
|
+
|
|
109
|
+
The sessions left running are the Claude Code sessions that have been idle for 24 hours or more, 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. A session that has done anything since is left running.
|
|
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.
|
|
112
|
+
|
|
95
113
|
### Codex's files
|
|
96
114
|
|
|
97
115
|
Agent Lookout reads Codex's folder: the one `AGENT_LOOKOUT_CODEX_HOME` names, otherwise the one Codex's own `CODEX_HOME` names, otherwise `~/.codex`. It runs no Codex program, changes no Codex setting and installs no hook. None of these files is documented by Codex. [docs/adapters/codex.md](docs/adapters/codex.md) records where each one comes from.
|
|
@@ -135,7 +153,32 @@ It reads only ordinary files of 4 KB or less, and on macOS and Linux it does not
|
|
|
135
153
|
|
|
136
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.
|
|
137
155
|
|
|
138
|
-
It reads nothing else in a repository: no other branch or reference, no `packed-refs`, no configuration, no index, no logs, no objects, and none of the files you work on.
|
|
156
|
+
It reads nothing else in a repository: no other branch or reference, no `packed-refs`, no configuration, no index, no logs, no objects, and none of the files you work on. The one exception is with `AGENT_LOOKOUT_PULL_REQUESTS=on`, when it also reads the repository's `config` and its remote's `HEAD`, as [`gh`](#gh) describes.
|
|
157
|
+
|
|
158
|
+
### `gh`
|
|
159
|
+
|
|
160
|
+
Only with `AGENT_LOOKOUT_PULL_REQUESTS=on`, Agent Lookout shows each session's pull request on github.com and its checks. It asks your own GitHub CLI, `gh`, for them. With the setting left out or `off`, which is the default, it reads none of the files below, never looks for `gh` and never runs it. Any other value leaves it off too, and Agent Lookout prints one line at start that names the setting.
|
|
161
|
+
|
|
162
|
+
To know where to look, it reads two more files in the git folder of each repository a session is in, the one [Git repositories](#git-repositories) finds, and writes nothing:
|
|
163
|
+
|
|
164
|
+
- `config`, of at most 64 KB, an ordinary file it does not follow as a link. From it, it keeps each remote's name and first `url`, the `gh-resolved` line that `gh repo set-default` writes, each branch's `remote` and `pushRemote`, and `remote.pushDefault`, and drops the rest of the file. Of a remote's address it keeps only the owner and the name of a repository on github.com, never the address itself, and never a user name, password or token written in it. It does not read your global git configuration.
|
|
165
|
+
- `refs/remotes/<remote>/HEAD`, of at most 4 KB, which names the remote's default branch.
|
|
166
|
+
|
|
167
|
+
It asks only about a branch of a repository whose remote is on github.com, and never about the default branch, the one that `HEAD` names, or `main` or `master` when it was never written. A remote on any other host, such as a GitHub Enterprise server, is never asked about. Nor is a branch whose name is only digits, with or without a `#` before them, such as `51` or `#51`, since `gh` would read it as the number of a pull request rather than as a branch.
|
|
168
|
+
|
|
169
|
+
For each repository and branch your sessions are on, it runs, at most once every 2 minutes and never on every poll:
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
gh pr view --repo github.com/<owner>/<repository> --json number,title,state,isDraft,statusCheckRollup -- <branch>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
where `<branch>` is the branch's name, or `<owner>:<branch>` for a branch pushed to a fork. `gh` is found on `PATH`, then at `/opt/homebrew/bin/gh`, `/usr/local/bin/gh`, `/opt/local/bin/gh` and `/usr/bin/gh`, and is started directly, by that full path, never through a shell, with stdin closed and a 15 second timeout, one question at a time. It is given the environment Agent Lookout was started with, less Agent Lookout's own settings, so it signs in with its own login, as it does in your terminal, with `GH_PROMPT_DISABLED`, `GH_NO_UPDATE_NOTIFIER`, `GH_NO_EXTENSION_UPDATE_NOTIFIER`, `GH_SPINNER_DISABLED` and `NO_COLOR` set, and `GH_FORCE_TTY`, `GH_DEBUG`, `DEBUG`, `GH_PAGER` and `PAGER` taken out. Agent Lookout never reads, keeps or passes on a token, and never reads `gh`'s own configuration or login.
|
|
176
|
+
|
|
177
|
+
`gh` then asks GitHub's API, over HTTPS, for that one pull request. What goes to GitHub is the repository's owner and name and the branch's name, with your login, as when you run the command yourself. Nothing about your sessions, their names, folders or what they are asking goes. What GitHub keeps of the request is governed by GitHub's terms, and what `gh` does besides by its own settings.
|
|
178
|
+
|
|
179
|
+
From the answer it keeps the pull request's number, its title, whether it is open, a draft, merged or closed, and how many of its checks are failing, pending and passing. It keeps no check's name, link or log, no body, comment, author or review. The title is cleaned of control characters and of the characters that change the direction of text, and cut to 200 characters. The link to the pull request is made from the repository and the number, not taken from GitHub's answer. All of it is kept in memory only, for as long as a session is on that branch, and is never written to disk, to the history or to the Events log. When `gh` is not there, is not signed in, or does not answer, nothing of what it printed is kept or shown: Settings says which, in words of Agent Lookout's own.
|
|
180
|
+
|
|
181
|
+
The pull request is in the session list the API serves on this computer, and so on the dashboard, and in answers of `agent-lookout mcp` and `agent-lookout status --json` as its number and how its checks stand, never its title, as [The MCP server](#the-mcp-server) says. No email, webhook post or notification holds it.
|
|
139
182
|
|
|
140
183
|
### `osascript`
|
|
141
184
|
|
|
@@ -149,7 +192,7 @@ Only when you start it with `agent-lookout --open`, Agent Lookout runs `/usr/bin
|
|
|
149
192
|
|
|
150
193
|
### Settings
|
|
151
194
|
|
|
152
|
-
It reads twenty-
|
|
195
|
+
It reads twenty-six 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_NOTIFICATIONS`, `AGENT_LOOKOUT_TMUX`, `AGENT_LOOKOUT_TERMINAL_JUMP`, `AGENT_LOOKOUT_STOP`, `AGENT_LOOKOUT_PULL_REQUESTS`, `AGENT_LOOKOUT_PORT`, `AGENT_LOOKOUT_HOST`, 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 [guide](docs/GUIDE.md#settings-you-can-change) says what each setting does.
|
|
153
196
|
|
|
154
197
|
## What it never reads
|
|
155
198
|
|
|
@@ -157,14 +200,15 @@ It reads twenty-four settings from the environment: `AGENT_LOOKOUT_CLAUDE_HOME`,
|
|
|
157
200
|
- Claude Code's transcripts, in `~/.claude/projects/` or anywhere else, beyond the end of a waiting session's own, as [Claude Code's transcripts](#claude-codes-transcripts) describes. Of what it reads there, it keeps one line about the tool the session is asking to use, and none of your prompts, the agent's replies, your code or the output of tools.
|
|
158
201
|
- Claude Code's settings, credentials, history and memory files.
|
|
159
202
|
- Codex's `auth.json`, `config.toml`, `history.jsonl`, its SQLite files (`*.sqlite`), its `log/` folder, `archived_sessions/` and compressed session files (`*.jsonl.zst`), and the Codex desktop app's `external_agent_session_imports.json` and `.codex-global-state.json`.
|
|
160
|
-
- In a git repository, anything but the `.git` file, `HEAD` and a worktree's `commondir` described under [Git repositories](#git-repositories).
|
|
203
|
+
- In a git repository, anything but the `.git` file, `HEAD` and a worktree's `commondir` described under [Git repositories](#git-repositories), and with `AGENT_LOOKOUT_PULL_REQUESTS=on`, the `config` and the remote's `HEAD` described under [`gh`](#gh).
|
|
204
|
+
- `gh`'s configuration, its login and any token, and your global git configuration.
|
|
161
205
|
- The files of any other application.
|
|
162
206
|
|
|
163
|
-
It runs no program but the `claude` binary, `ps`, `tmux`, on macOS `osascript`, to show a notification and to bring a tab of Terminal or iTerm2 forward,
|
|
207
|
+
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`, and only with `AGENT_LOOKOUT_PULL_REQUESTS=on`, `gh`. 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. 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 two 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, and, when you press Stop and confirm, whether a Claude Code session's process runs, as [Stopping a session](#stopping-a-session) describes.
|
|
164
208
|
|
|
165
209
|
## Network
|
|
166
210
|
|
|
167
|
-
With email and the webhook off, which is the default, the only network traffic Agent Lookout's own code makes is between its own server and the dashboard in your browser, or the `agent-lookout status` and `agent-lookout mcp` commands, on the same machine. With email set up, it also connects to the mail server you named, once for each email, as [Email](#email) describes. With a webhook address set, it also connects to that address, once for each post, as [Webhook](#webhook) describes. One more connection never leaves the machine either: before `npm start` or `agent-lookout` begins listening, it connects once to its own address and port to see whether another program already answers there, and sends nothing over that connection. There is no telemetry, no analytics, no crash reporting and no account. There is no update check either, except in the Mac app, which asks GitHub about once a day whether a newer version of it is out, as [Updates (Mac app only)](#updates-mac-app-only) describes. Fonts and scripts are bundled, so the page loads nothing from the internet.
|
|
211
|
+
With email and the webhook off, which is the default, the only network traffic Agent Lookout's own code makes is between its own server and the dashboard in your browser, or the `agent-lookout status` and `agent-lookout mcp` commands, on the same machine. With email set up, it also connects to the mail server you named, once for each email, as [Email](#email) describes. With a webhook address set, it also connects to that address, once for each post, as [Webhook](#webhook) describes. With `AGENT_LOOKOUT_PULL_REQUESTS=on`, it runs `gh`, which connects to GitHub, at most once every 2 minutes for each repository and branch your sessions are on, as [`gh`](#gh) describes. One more connection never leaves the machine either: before `npm start` or `agent-lookout` begins listening, it connects once to its own address and port to see whether another program already answers there, and sends nothing over that connection. There is no telemetry, no analytics, no crash reporting and no account. There is no update check either, except in the Mac app, which asks GitHub about once a day whether a newer version of it is out, as [Updates (Mac app only)](#updates-mac-app-only) describes. Fonts and scripts are bundled, so the page loads nothing from the internet.
|
|
168
212
|
|
|
169
213
|
Started with `npx agent-lookout`, npm itself contacts its registry: to download the package the first time, and each time after to ask whether a newer version is out, as it does for any package it runs. 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.
|
|
170
214
|
|
|
@@ -174,11 +218,11 @@ The `claude agents` command is Claude Code's own program, and it may contact Ant
|
|
|
174
218
|
|
|
175
219
|
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.
|
|
176
220
|
|
|
177
|
-
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.
|
|
221
|
+
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.
|
|
178
222
|
|
|
179
|
-
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,
|
|
223
|
+
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, and 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). The Mac app opens no port, so there only its own window can do any of this. `AGENT_LOOKOUT_STOP=off` takes stopping away.
|
|
180
224
|
|
|
181
|
-
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
|
|
225
|
+
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 and the ones Stop session and End 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.
|
|
182
226
|
|
|
183
227
|
## Notifications
|
|
184
228
|
|
|
@@ -379,7 +423,7 @@ For each tool the agent calls, it asks Agent Lookout's own server for the list o
|
|
|
379
423
|
|
|
380
424
|
It answers the app that started it, over stdout, and nothing and nobody else. An answer is one of three:
|
|
381
425
|
|
|
382
|
-
- For each session: its ID, its name, its agent, 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. Never what a waiting session is asking, which is read from its transcript.
|
|
426
|
+
- For each session: its ID, its name, its agent, 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.
|
|
383
427
|
- 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.
|
|
384
428
|
- 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.
|
|
385
429
|
|
|
@@ -387,7 +431,7 @@ When Agent Lookout cannot be reached, the answer is one sentence that says so, w
|
|
|
387
431
|
|
|
388
432
|
### What happens to an answer
|
|
389
433
|
|
|
390
|
-
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 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`.
|
|
434
|
+
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`.
|
|
391
435
|
|
|
392
436
|
### What is kept
|
|
393
437
|
|
|
@@ -397,7 +441,7 @@ Nothing. Each answer is worked out from one reading of the list and is gone once
|
|
|
397
441
|
|
|
398
442
|
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. Apart from that, its own code writes no files, except the Mac app's, below.
|
|
399
443
|
|
|
400
|
-
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. 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, and what the dashboard pages last said about notifications.
|
|
444
|
+
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. 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.
|
|
401
445
|
|
|
402
446
|
### The history
|
|
403
447
|
|
|
@@ -405,7 +449,7 @@ The history is kept in the folder `~/.agent-lookout/history`, beside the folder
|
|
|
405
449
|
|
|
406
450
|
It writes there what it already holds in memory for the Events log and the charts, and nothing else:
|
|
407
451
|
|
|
408
|
-
- Each event: its ID, its time, the session's ID and name, whether the session appeared, changed status or
|
|
452
|
+
- Each event: its ID, its time, the session's ID and name, whether the session appeared, changed status, ended or was stopped from Agent Lookout, the status it changed from and to, how serious the change was, and for a session that was stopped, that Agent Lookout stopped it. A session's ID is its agent's own ID for it, or the name of its status file.
|
|
409
453
|
- Each history point, one for each poll: its time, and how many sessions were waiting on you, working, idle, and in all.
|
|
410
454
|
- When Agent Lookout started writing, and when the history was cleared.
|
|
411
455
|
|
|
@@ -431,11 +475,11 @@ The tools that run it write files of their own. None of these holds session data
|
|
|
431
475
|
|
|
432
476
|
The Mac app keeps the history in the same folder as `npx agent-lookout` and `npm start`, and four files of its own. `window-state.json`, in `~/Library/Application Support/Agent Lookout/`, holds the window's place and size and the colour of the theme it last showed. `update-state.json`, beside it, holds whether it checks for updates by itself, when it last checked, the last version it told you of and, during an install, the version being installed, as [Updates (Mac app only)](#updates-mac-app-only) says, and a newer version it downloads waits in the system's temporary folder until it is installed or the app quits. `menu-bar-state.json`, beside it, holds whether its icon is shown in the menu bar. Its log, `~/Library/Logs/Agent Lookout/main.log`, holds the errors it met and the lines `npm start` would print, such as the one that says an email setting is wrong. None of them holds a session's name, though an error in the log can name a file the app could not read. Electron, which the app is built on, keeps the page's local storage, below, and caches of its own in the first folder.
|
|
433
477
|
|
|
434
|
-
The dashboard saves
|
|
478
|
+
The dashboard saves seven values in your browser's local storage. Your theme choice is under the key `agent-lookout-theme`. Whether notifications are on is under the key `agent-lookout-notifications`, as `on` or `off`, and is written only when you turn them on or off. The events that send one are under the key `agent-lookout-notification-events`, as their names separated by commas, such as `needs-you,finished`, and are written only when you switch one. The apps the page has said macOS will ask about, when you first jumped to a tab of one, are under the key `agent-lookout-automation-note`, as `Terminal`, `iTerm2` or both separated by a comma. The last time the Events log was on screen is under the key `agent-lookout-last-looked`, as a number of milliseconds since 1970, and is written when the page goes out of sight or is closed. It is what the line in the Events log that marks where you left off is drawn from, and while that line still shows, the time kept is the line's own. It holds nothing about any session or event. Whether the Sessions card shows the list, the list grouped by repository or the board is under the key `agent-lookout-sessions-layout`, as `list`, `repositories` or `board`, and is written only when you choose one. The sessions left running that you hid until they change are under the key `agent-lookout-hidden-sessions`, as a list of each one's ID and the moment its idle began, at most 100, and are written only when you hide one. All seven belong to one browser at one address.
|
|
435
479
|
|
|
436
480
|
## What is on screen
|
|
437
481
|
|
|
438
|
-
Session names, folder paths, repository names, branch names and what a waiting session is asking, such as a command or a file, can show what you are working on. Check a screenshot before you share it.
|
|
482
|
+
Session names, folder paths, repository names, branch names, pull request titles and what a waiting session is asking, such as a command or a file, can show what you are working on. Check a screenshot before you share it.
|
|
439
483
|
|
|
440
484
|
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.
|
|
441
485
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Agent Lookout shows the AI agent sessions on your Mac or Linux 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 only
|
|
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 or answers a session, and it stops one only when you press Stop and confirm: 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
|
|
|
@@ -18,7 +18,9 @@ It finds Claude Code and Codex sessions with no setup, and the sessions of any o
|
|
|
18
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
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
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. |
|
|
21
22
|
| [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. |
|
|
23
|
+
| [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. |
|
|
22
24
|
| [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. |
|
|
23
25
|
| [`agent-lookout status`](docs/GUIDE.md#in-the-terminal) | Prints which sessions need you, for a terminal, a tmux status line or a script. |
|
|
24
26
|
| [`agent-lookout mcp`](docs/GUIDE.md#for-your-agents) | Lets an AI agent ask which sessions need you. Its tools only read. |
|
|
@@ -73,7 +75,7 @@ Kept in Applications, it updates itself: about once a day it asks GitHub whether
|
|
|
73
75
|
npx agent-lookout
|
|
74
76
|
```
|
|
75
77
|
|
|
76
|
-
The first time, npm names the package and asks `Ok to proceed? (y)`. Press Enter. npm downloads
|
|
78
|
+
The first time, npm names the package and asks `Ok to proceed? (y)`. Press Enter. npm downloads under 2 MB and keeps it in its cache. Then Agent Lookout prints:
|
|
77
79
|
|
|
78
80
|
```text
|
|
79
81
|
Agent Lookout is running at http://127.0.0.1:4777
|
|
@@ -162,7 +164,7 @@ It asks `http://127.0.0.1:4777`, then `http://localhost:5173`. If Agent Lookout
|
|
|
162
164
|
|
|
163
165
|
## For your agents
|
|
164
166
|
|
|
165
|
-
`agent-lookout mcp` is a [Model Context Protocol](https://modelcontextprotocol.io) server. It lets an AI agent ask which sessions are running and which need you, so one agent can keep track of the others. Its three tools, `list_sessions`, `sessions_needing_you` and `sources`, only read. It asks the Agent Lookout that is running, and starts nothing.
|
|
167
|
+
`agent-lookout mcp` is a [Model Context Protocol](https://modelcontextprotocol.io) server. It lets an AI agent ask which sessions are running and which need you, so one agent can keep track of the others. Its three tools, `list_sessions`, `sessions_needing_you` and `sources`, only read: none of them can stop a session. It asks the Agent Lookout that is running, and starts nothing.
|
|
166
168
|
|
|
167
169
|
To add it to Claude Code for all your folders, run this once:
|
|
168
170
|
|
|
@@ -190,6 +192,7 @@ AGENT_LOOKOUT_CLAUDE_FEED=off npx agent-lookout
|
|
|
190
192
|
| `AGENT_LOOKOUT_CLAUDE_FEED=off` | Never runs the `claude` command. Sessions come from Claude Code's session files alone. |
|
|
191
193
|
| `AGENT_LOOKOUT_WAITING_TEXT=off` | Never opens a Claude Code transcript. A waiting session shows its reason alone. |
|
|
192
194
|
| `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`. |
|
|
195
|
+
| `AGENT_LOOKOUT_STOP=off` | Takes away Stop and the ending of sessions left running. No session is ever stopped from Agent Lookout. |
|
|
193
196
|
|
|
194
197
|
[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.
|
|
195
198
|
|
|
@@ -197,6 +200,7 @@ AGENT_LOOKOUT_CLAUDE_FEED=off npx agent-lookout
|
|
|
197
200
|
|
|
198
201
|
By default Agent Lookout itself sends nothing anywhere: no telemetry, no analytics, no crash reports and no account. The one exception is the Mac app, which asks GitHub about once a day whether a newer version of it is out and sends nothing about your sessions: Settings turns that off, [Updates (Mac app only)](PRIVACY.md#updates-mac-app-only) says what it sends, and `npx agent-lookout` and the repository never check. Its fonts and scripts are bundled, so the page loads nothing from the internet. It keeps the Events log and the counts behind the charts on this computer, in `~/.agent-lookout/history`, so they are still there after a restart: for 8 days and up to 20 MB, with each session's name and status changes and no folder path, prompt or anything a waiting session is asking. Clear history in Settings deletes them, and `AGENT_LOOKOUT_HISTORY=off` keeps them in memory only. [PRIVACY.md](PRIVACY.md) lists everything it reads, runs, keeps and can send.
|
|
199
202
|
|
|
203
|
+
- Pull requests are off until 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, so Agent Lookout never sees a token. It asks at most once every 2 minutes for each repository and branch, only for a remote on github.com and never about the default branch. [`gh`](PRIVACY.md#gh) says what it reads and keeps.
|
|
200
204
|
- 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.
|
|
201
205
|
- 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.
|
|
202
206
|
- 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.
|
|
@@ -205,11 +209,11 @@ By default Agent Lookout itself sends nothing anywhere: no telemetry, no analyti
|
|
|
205
209
|
- `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.
|
|
206
210
|
- 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.
|
|
207
211
|
|
|
208
|
-
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, do what the Jump button does, and
|
|
212
|
+
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, do what the Jump button does, clear the history, and stop a Claude Code session as the Stop button does. The Mac app opens no port, so there only its own window can. It writes to no agent's files. It changes two 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. `AGENT_LOOKOUT_STOP=off` takes Stop away.
|
|
209
213
|
|
|
210
214
|
## What it does not do yet
|
|
211
215
|
|
|
212
|
-
-
|
|
216
|
+
- It cannot resume or answer a session. It stops a Claude Code session only when you press Stop and confirm, and not one in the desktop app. An agent using `agent-lookout mcp` can do none of these.
|
|
213
217
|
- It shows only sessions on this computer. Cloud sessions, Codex cloud tasks and chats in a browser tab do not appear.
|
|
214
218
|
- 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.
|
|
215
219
|
- 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).
|
|
@@ -235,4 +239,4 @@ Bug reports, fixes and support for other agents are welcome. For anything larger
|
|
|
235
239
|
|
|
236
240
|
## License
|
|
237
241
|
|
|
238
|
-
Agent Lookout is [MIT licensed](LICENSE). The package's `dist/THIRD-PARTY-LICENSES.md` lists the licences of the libraries and fonts the dashboard
|
|
242
|
+
Agent Lookout is [MIT licensed](LICENSE). The package's `dist/THIRD-PARTY-LICENSES.md` lists the licences of the libraries and fonts the dashboard and the command include. It is an unofficial project, not affiliated with or endorsed by Anthropic, OpenAI or any other agent maker. See [DISCLAIMER.md](DISCLAIMER.md).
|
package/SECURITY.md
CHANGED
|
@@ -12,7 +12,7 @@ The project has one maintainer, so replies are best effort. Fixes land on `main`
|
|
|
12
12
|
|
|
13
13
|
## What the app handles
|
|
14
14
|
|
|
15
|
-
Agent Lookout reads metadata about the Claude Code and Codex sessions on your machine: names, working directories, statuses and, for Claude Code, process IDs. For each session's folder it reads which git branch is checked out, and which repository the folder belongs to, from the repository's `.git` entry, `HEAD` and a worktree's `commondir` alone, and runs no git command. On a Mac it also lists every process's ID, parent, terminal and program name with `ps` when a new Claude Code session appears, to find the Terminal or iTerm2 tab it runs in, and keeps only the app and the session's terminal. It serves that to the dashboard over HTTP on a loopback address. Of Claude Code's transcripts it reads only the end of a waiting session's own, opened without following a link, and keeps one line of it, what the session is asking, until the wait ends. That line goes to the dashboard and to notifications on this machine, never to an email, a webhook post or `agent-lookout mcp`. It does open Codex's session files, which hold whole conversations, and keeps only when turns started and ended and a few fields. It writes to no agent's files. It also reads the folder of status files, `~/.agent-lookout/sessions` or the one `AGENT_LOOKOUT_STATUS_DIR` names, where any program can write a small JSON file to show one of its sessions, and it writes nothing there. It keeps the Events log and the counts behind its charts in its own folder, `~/.agent-lookout/history`, which it makes with mode 700, in files of mode 600 that it neither reads nor writes through a link. They hold session IDs and names, statuses and times, and never what a waiting session is asking. `AGENT_LOOKOUT_HISTORY=off` keeps them in memory only. [PRIVACY.md](PRIVACY.md) lists everything it reads, runs and keeps.
|
|
15
|
+
Agent Lookout reads metadata about the Claude Code and Codex sessions on your machine: names, working directories, statuses and, for Claude Code, process IDs. For each session's folder it reads which git branch is checked out, and which repository the folder belongs to, from the repository's `.git` entry, `HEAD` and a worktree's `commondir` alone, and runs no git command. On a Mac it also lists every process's ID, parent, terminal and program name with `ps` when a new Claude Code session appears, to find the Terminal or iTerm2 tab it runs in, and keeps only the app and the session's terminal. It serves that to the dashboard over HTTP on a loopback address. Of Claude Code's transcripts it reads only the end of a waiting session's own, opened without following a link, and keeps one line of it, what the session is asking, until the wait ends. That line goes to the dashboard and to notifications on this machine, never to an email, a webhook post or `agent-lookout mcp`. It does open Codex's session files, which hold whole conversations, and keeps only when turns started and ended and a few fields. It writes to no agent's files. It ends a Claude Code session's process only when the person presses Stop and confirms, by the route described below, and never on its own. It also reads the folder of status files, `~/.agent-lookout/sessions` or the one `AGENT_LOOKOUT_STATUS_DIR` names, where any program can write a small JSON file to show one of its sessions, and it writes nothing there. It keeps the Events log and the counts behind its charts in its own folder, `~/.agent-lookout/history`, which it makes with mode 700, in files of mode 600 that it neither reads nor writes through a link. They hold session IDs and names, statuses and times, and never what a waiting session is asking. `AGENT_LOOKOUT_HISTORY=off` keeps them in memory only. [PRIVACY.md](PRIVACY.md) lists everything it reads, runs and keeps.
|
|
16
16
|
|
|
17
17
|
With notifications turned on in Settings, the dashboard page hands a session's name and a fixed text, the reason it waits or Finished, Failed or Ended, to the browser's Notifications API, which passes them to the operating system. When no dashboard page is open, the local server shows the notification itself on macOS: it runs `/usr/bin/osascript` with a fixed script, and passes the name and the text to that script as arguments. Each dashboard page tells the server whether its notifications are on, in a header on its requests, and the server shows its own only while the last page to say so said they are on, or `AGENT_LOOKOUT_NOTIFICATIONS=on` was set and no page has said anything. Nothing is sent over the network for any of this. [PRIVACY.md](PRIVACY.md#notifications) has the details.
|
|
18
18
|
|
|
@@ -20,7 +20,7 @@ Email notifications are off unless they are set up in the environment Agent Look
|
|
|
20
20
|
|
|
21
21
|
Webhook posts are off unless `AGENT_LOOKOUT_WEBHOOK_URL` is set in the environment Agent Lookout starts with. Then, for each event chosen, the collector sends one short JSON post to that one address, over HTTPS with the certificate checked, or over plain HTTP only to `127.0.0.1` or `localhost`. It holds the session's name, what happened, when, the name of its project folder, its app and its agent, and, for a wait with `AGENT_LOOKOUT_WEBHOOK_ASKING=on`, what the session is asking. It follows no redirect and tries nothing twice. The address is itself a secret: whoever has a Slack incoming webhook's address can post to its channel. So it lives in the environment of the Agent Lookout process and nowhere else: it is never written to a file, sent to the dashboard or printed. `GET /api/webhook` tells the dashboard only whether the webhook is on, the host, the events, the delay, whether a wait's post says what the session is asking, and how the last post went. [PRIVACY.md](PRIVACY.md#webhook) has the details.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Four routes of the local API change something: `POST /api/jump`, which the Jump button of a session in tmux, Terminal or iTerm2 sends, `POST /api/history/clear`, which the Clear history button in Settings sends, and `POST /api/sessions/stop` and `POST /api/sessions/clean-up`, which Stop session and the ending of the sessions left running send. Every other route only reads. The two that stop sessions are described after the jump route, below. `POST /api/history/clear` deletes the history files in Agent Lookout's own folder and empties the Events log and the history in memory. Its body is exactly `{}`, nothing in it names a file, and it makes the same checks as the jump route, below, with `X-Agent-Lookout-Action: clear-history`. The rest of this part is about `POST /api/jump`. For a session in tmux it can change three things, all inside tmux: which pane is selected in its window, which window is selected in its tmux session, and which tmux session each attached terminal is showing. For a session in a tab of Terminal or iTerm2, on macOS, it can bring that tab forward: select it in its window, bring the window back from the Dock if it was minimised and in front of the app's others, and bring the app to the front. It sends no keys, runs nothing inside a pane or a tab, starts no tmux server and starts no app.
|
|
24
24
|
|
|
25
25
|
A request to it names a session by its ID and nothing else. The server looks that session up in its own list and takes the pane it found for that session's process when it last asked tmux. It checks that the pane's ID is a `%` followed by digits, and gives it to a fixed list of tmux commands: `select-window`, `select-pane`, `display-message -p`, `list-clients` and `switch-client`. Nothing from the request is passed to tmux, and tmux is started directly, never through a shell. So the route can never be made to run another program, another tmux command or a command with other arguments. The most a request can do is choose which of the panes already found for a listed session is selected.
|
|
26
26
|
|
|
@@ -36,11 +36,20 @@ On top of the checks every route makes, the route answers only a request that:
|
|
|
36
36
|
|
|
37
37
|
It makes one jump a second, and one at a time. `AGENT_LOOKOUT_TMUX=off` stops Agent Lookout running tmux, and the route then finds no pane for any session. `AGENT_LOOKOUT_TERMINAL_JUMP=off` stops it looking for tabs, and the route then brings no tab forward. [PRIVACY.md](PRIVACY.md#tmux) lists each command, and [Terminal and iTerm2](PRIVACY.md#terminal-and-iterm2) the script.
|
|
38
38
|
|
|
39
|
+
`POST /api/sessions/stop` ends one Claude Code session's process, and `POST /api/sessions/clean-up` ends up to 20 sessions left running, idle for a day or more. Each passes the checks above, with `X-Agent-Lookout-Action: stop` or `clean-up`, and a body of 1,024 bytes or less that is exactly `{"sessionId": "..."}`, or of 8 KiB or less that is exactly `{"sessions": [{"sessionId": "...", "statusSince": ...}]}`. A request names sessions, and for a clean-up the moment each one's idle began, and nothing else. The server looks each session up in its own list and acts on what the Claude Code adapter found for it: its process ID, the start time its registry file recorded and, for a background job, the job's ID, none of which is sent to the page or read from a request. Before it acts, it makes every check again at that moment, with nothing remembered:
|
|
40
|
+
|
|
41
|
+
- It reads the session's registry file again, an ordinary file it opens without following a link. The file must still name that session and that process, be of kind `interactive` or `bg`, the kind it had, and record the same start time. A file that names no kind, or another, is refused.
|
|
42
|
+
- It runs `ps` for that process again, and acts only when `ps` gives the same start time the file recorded, a second apart at most, since `ps` gives it in whole seconds. A start time `ps` does not give, or that cannot be compared, is refused as not confirmed. So a pid that has been handed to another program is not signalled unless that program started within a second of the session, and the few milliseconds before the signal, below, are a known gap.
|
|
43
|
+
- It refuses process 1, its own process, the process it was started from and every process above that, which it finds by following its own process up through its parents in `ps -A -o pid=,ppid=` at that moment, a process of another user's, and a session in Claude Code's desktop app.
|
|
44
|
+
- For a clean-up, the file, and the server's own latest list of sessions, which can come from `claude agents`, must also still say the session is idle, since the moment the page sent, and that moment must be 24 hours or more ago. A session that has done anything since is left running.
|
|
45
|
+
|
|
46
|
+
Then it sends SIGTERM to that one process, never SIGKILL, and waits up to 10 seconds for it to end, or, for a background job, runs the `claude` binary it already runs for `claude agents`, directly, never through a shell, with stdin closed and a 10 second timeout, as `claude stop` and the job's ID, which must be letters, digits, dashes and underscores, starting with a letter or a digit. One stop or clean-up is made at a time, a second apart. The time between the `ps` check and the signal is a few milliseconds, and for a pid to be given to another program in that time, the process would have to end and the system would have to give out every other pid first. macOS has no way to close that gap entirely. `AGENT_LOOKOUT_STOP=off` removes both routes. [Stopping a session](PRIVACY.md#stopping-a-session) has the rest.
|
|
47
|
+
|
|
39
48
|
The Mac app answers four more routes, under `/api/app/` on its own address, which no port reaches and which `npm start` and the npm package do not have: `GET /api/app/update`, and three POSTs that check GitHub for a newer version, install the one that is ready, and turn the daily check on or off. Each POST passes the checks above, with an `X-Agent-Lookout-Action` of its own, and a body of 256 bytes or less that is exactly what it needs. The app's only requests off the machine are the update check's and its download's, over HTTPS, with the certificate checked, to GitHub and the two hosts GitHub redirects a release's downloads to, and to no other address, a redirect's included. A download must have the size and SHA-512 the release's `latest-mac.yml` gives, and the bundle in it must be this app, by its bundle identifier, at the version offered, with no link where the bundle, its `Contents` or its `Info.plist` should be. Only Install and Restart starts the helper that replaces the app: `/bin/sh` with a fixed script, and the app's process ID and three paths as its arguments, two of them in the app's own temporary folder. Nothing from the network or from a request reaches its arguments or any command. The app is not signed with a Developer ID yet, so a download is vouched for by the release it comes from and the hash in that release, and is as safe as the project's GitHub releases are.
|
|
40
49
|
|
|
41
|
-
`agent-lookout mcp` is a Model Context Protocol server for an agent that keeps track of your other agents. The agent's app starts it and speaks to it over stdin and stdout, so it opens no port. For each tool call it reads `GET /api/sessions` from the local server, at a loopback address only, with no `Origin` and no notifications header, exactly as `agent-lookout status` does, and answers the app with what it read. Its three tools only read: none of them reaches `POST /api/jump` or `POST /api/
|
|
50
|
+
`agent-lookout mcp` is a Model Context Protocol server for an agent that keeps track of your other agents. The agent's app starts it and speaks to it over stdin and stdout, so it opens no port. For each tool call it reads `GET /api/sessions` from the local server, at a loopback address only, with no `Origin` and no notifications header, exactly as `agent-lookout status` does, and answers the app with what it read. Its three tools only read: none of them reaches `POST /api/jump`, `POST /api/history/clear`, `POST /api/sessions/stop` or `POST /api/sessions/clean-up`, changes a notification or changes anything else. A session's name, agent, folder and branch are text that other programs wrote, and the client is a model that takes instructions from text. So each tool's description and each answer say that this text is data, never instructions, the one-sentence summary puts each name in quotation marks, and escape sequences and control characters are taken out of every text, as `agent-lookout status` does. So are characters that show nothing, such as zero-width spaces and Unicode's tag characters, in which words can be hidden from a person but not from a model.
|
|
42
51
|
|
|
43
|
-
The local API has no token, and the MCP server adds none, though one was suggested for it. The server opens no port of its own, and the API it reads is the same loopback API that the dashboard and `agent-lookout status` read without one. Websites and other computers are already kept away from that API by the `Host` and `Origin` checks and by its listening on loopback alone. Against websites and other computers a token would add nothing to those checks, and programs running as you could read a token as easily as the API. It could keep out other accounts on a shared computer, the known limit listed below, and is left for later. An API that can be reached some other way, such as from another computer, would need one too, and Agent Lookout has none. [docs/API.md](docs/API.md) describes every route and its checks.
|
|
52
|
+
The local API has no token, and the MCP server adds none, though one was suggested for it. The server opens no port of its own, and the API it reads is the same loopback API that the dashboard and `agent-lookout status` read without one. Websites and other computers are already kept away from that API by the `Host` and `Origin` checks and by its listening on loopback alone. Against websites and other computers a token would add nothing to those checks, and programs running as you could read a token as easily as the API. It could keep out other accounts on a shared computer, the known limit listed below, which includes another account asking the server to stop your Claude Code sessions, and is left for later. An API that can be reached some other way, such as from another computer, would need one too, and Agent Lookout has none. [docs/API.md](docs/API.md) describes every route and its checks.
|
|
44
53
|
|
|
45
54
|
Session names and folder paths can be sensitive. The main risk is that something other than your own browser reads them.
|
|
46
55
|
|
|
@@ -75,6 +84,7 @@ Session names and folder paths can be sensitive. The main risk is that something
|
|
|
75
84
|
- In the Mac app, a request, a release or anything from the network that makes it run anything but `/usr/bin/ditto`, `/usr/bin/plutil` and its fixed update helper, passes them arguments it did not make itself, installs a download whose size or SHA-512 is not the one the release gives or whose bundle is not Agent Lookout at the version offered, installs anything before Install and Restart is pressed, or makes a request to any host but GitHub's three for a release.
|
|
76
85
|
- A website, or a page served from anywhere but this machine, making the app select a tmux pane or bring a tab of Terminal or iTerm2 forward.
|
|
77
86
|
- A request to `POST /api/jump` that makes tmux do anything but select a pane found for a listed session, its window and its tmux session: running a command, sending keys, or reaching any other pane.
|
|
87
|
+
- A request to `POST /api/sessions/stop` or `POST /api/sessions/clean-up` that signals any process but a listed Claude Code session's own, one whose registry file and start time were not confirmed at that moment, or one in the desktop app, that sends any signal but SIGTERM, that runs `claude` with any arguments but `stop` and a job's ID found for a listed session, or that ends a session that was not idle since the moment the page sent. Also a website, or a page served from anywhere but this machine, making the app stop a session.
|
|
78
88
|
- A session's name, a tmux session's name, or anything else from a session or from tmux, that `tmux` reads as a command, a target or an option.
|
|
79
89
|
- A request to `POST /api/jump` that makes `osascript` run any script but the fixed one for Terminal or iTerm2, or with any argument but a terminal found for a listed session, or that makes Terminal or iTerm2 do anything but bring a tab forward: running a command, sending keys or text, or reading what a tab shows.
|
|
80
90
|
- A session name, or anything else from a session, that `osascript` reads as AppleScript or as one of its options instead of showing it as text.
|
|
@@ -82,14 +92,14 @@ Session names and folder paths can be sensitive. The main risk is that something
|
|
|
82
92
|
- A notification, or the browser's question about allowing them, appearing when you have not turned notifications on, in Settings or with `AGENT_LOOKOUT_NOTIFICATIONS=on`.
|
|
83
93
|
- A notification that holds anything but the session's name and the reason, or Finished, Failed or Ended, or that makes the browser fetch anything.
|
|
84
94
|
- A page at another address reading or steering the dashboard's notifications, or turning the server's own on or off.
|
|
85
|
-
- A tool of `agent-lookout mcp` that acts: that reaches `POST /api/jump
|
|
95
|
+
- A tool of `agent-lookout mcp` that acts: that reaches `POST /api/jump` or a route that stops a session, sends the notifications header, or changes anything in Agent Lookout, in another tool or on this computer.
|
|
86
96
|
- `agent-lookout mcp` reading anything but `GET /api/sessions` from Agent Lookout at a loopback address, asking an address that is not loopback, opening a port, or making any other connection.
|
|
87
97
|
- Text from a session reaching the app that started `agent-lookout mcp` without being marked as data: a tool description or an answer that does not say it is untrusted text, a name outside its quotation marks in the summary, or a name, agent, folder, branch or source detail with an escape sequence, control character or invisible character such as a Unicode tag character left in it.
|
|
88
98
|
- Anything `agent-lookout mcp` writes to stdout that is not the protocol's own message, or an answer that holds more than PRIVACY.md lists, such as a session's whole folder path.
|
|
89
99
|
|
|
90
100
|
## Out of scope
|
|
91
101
|
|
|
92
|
-
- Other programs on the same machine reading the local API, sending it the header that turns the server's notifications on or off,
|
|
102
|
+
- Other programs on the same machine reading the local API, sending it the header that turns the server's notifications on or off, asking it to select a tmux pane or bring a tab forward, or asking it to stop a Claude Code session, with every check it makes for the Stop button. The API has no authentication, so any local process can request it, and on a shared computer that includes other user accounts. This is a known limit of this version. A program running as you could end your processes itself, but on a shared computer another account can also ask this server to stop your sessions, which it could not do itself. On such a computer, use the Mac app, which opens no port, so only its own window can ask, or set `AGENT_LOOKOUT_STOP=off`, which takes stopping away.
|
|
93
103
|
- A program on this machine that names itself after Terminal or iTerm2 in the list of processes, and so gives a session under it a Jump button. Pressing it asks the real app for a tab on that session's terminal, which it does not have.
|
|
94
104
|
- A notification the server showed staying in Notification Centre after its session has moved on. The server cannot take one down, and PRIVACY.md says so.
|
|
95
105
|
- The dev server started with Vite's `--host` flag, which makes it listen on the network. `npm start` refuses to listen on anything but loopback.
|