@hanskristoffer/agentpool 0.4.0 → 0.6.0
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/README.md +68 -15
- package/package.json +15 -5
package/README.md
CHANGED
|
@@ -4,13 +4,22 @@ One daemon per machine that:
|
|
|
4
4
|
|
|
5
5
|
- pools several **Claude** and **Codex** subscriptions and moves to the next account when one hits its limit;
|
|
6
6
|
- hosts **MCP servers** and gives each GitHub repo its own set (e.g. a separate PostHog project per repo), plus general ones for every repo;
|
|
7
|
-
- **shares** all of it between your machines over Tailscale, and keeps working when the other machines are offline.
|
|
7
|
+
- **shares** all of it between your machines over Tailscale or an end-to-end encrypted relay, and keeps working when the other machines are offline.
|
|
8
8
|
|
|
9
|
-
T3 Code (or plain Claude Code / Codex) runs the sessions; agentgate sits underneath. The optional **Tauri macOS app** controls your local or remote setup. The daemon and CLI work independently, including on headless Linux servers. There is no web UI. See [
|
|
9
|
+
T3 Code (or plain Claude Code / Codex) runs the sessions; agentgate sits underneath. The optional **Tauri macOS app** controls your local or remote setup. The daemon and CLI work independently, including on headless Linux servers. There is no web UI. See [operations and distribution checks](docs/operations.md).
|
|
10
|
+
|
|
11
|
+
## Using the Claude Desktop app
|
|
12
|
+
|
|
13
|
+
Agentgate works with Claude Desktop without any terminal: open the Agentgate app, choose **Set up this machine**, then **Accounts**, which has a **Claude Desktop** panel. Choose one of two ways:
|
|
14
|
+
|
|
15
|
+
- **Switch accounts**: Claude Desktop stays signed in to your full Claude account (Chat, Cowork, Code). Agentgate keeps a saved login per account on this Mac and switches with one click, from the app or the menu bar. Desktop restarts when you switch.
|
|
16
|
+
- **Share automatically**: Claude Desktop's Code tab uses whichever subscription has room and moves on by itself. Desktop runs a separate local profile without Chat.
|
|
17
|
+
|
|
18
|
+
Agentgate's MCP servers also work in Desktop's Code tab. See [Using Agentgate with Claude Desktop](docs/claude-desktop.md).
|
|
10
19
|
|
|
11
20
|
## Install
|
|
12
21
|
|
|
13
|
-
Requirements: Linux or macOS, [Tailscale](https://tailscale.com)
|
|
22
|
+
Requirements: Linux or macOS, [Tailscale](https://tailscale.com) or a relay (see below) to connect machines, `claude` and/or `codex` CLIs for logging in, and Node (`npx`) or uv (`uvx`) for any stdio MCP servers you add.
|
|
14
23
|
|
|
15
24
|
```sh
|
|
16
25
|
npm install -g @hanskristoffer/agentpool # installs the `agentgate` command (and an `agentpool` alias)
|
|
@@ -36,20 +45,30 @@ agentgate service install # launchd (macOS) or systemd --user (Linux)
|
|
|
36
45
|
|
|
37
46
|
You can do every setup step with the CLI. To use the native app, build it with `bun run build:desktop` and open **Agentgate.app**. It connects to `http://127.0.0.1:7878` by default. On a fresh machine, **Set up this machine** installs the bundled CLI in `~/.config/agentgate/bin`, initializes the store, and starts a launchd service. Add that folder to your shell PATH to use the CLI. Closing or removing the app leaves that service and its CLI running.
|
|
38
47
|
|
|
39
|
-
The app has Accounts, MCP servers, Projects, Machines, and Settings screens. **Settings → Configure coding tools** generates the Claude/Codex folders and T3 settings. The app's service and coding-tool controls apply only to its configured local daemon; remote setup and services use the CLI on that machine.
|
|
48
|
+
The app has Accounts, MCP servers, Skills, Projects, Machines, and Settings screens. **Settings → Configure coding tools** generates the Claude/Codex folders and T3 settings. The app's service and coding-tool controls apply only to its configured local daemon; remote setup and services use the CLI on that machine.
|
|
40
49
|
|
|
41
50
|
## A second machine (e.g. an always-on server)
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
There are two ways to connect machines, and a machine can use both:
|
|
53
|
+
|
|
54
|
+
- **Same network (Tailscale):** both machines are on your tailnet. Pairing uses a code that expires after 10 minutes.
|
|
55
|
+
- **Relay:** works across any network, without Tailscale. Every record is encrypted before it leaves the machine; the relay stores only ciphertext and can't read your credentials.
|
|
56
|
+
|
|
57
|
+
On the first machine, run `agentgate pair`. In a terminal it asks which method to use; `--tailnet` and `--relay` skip the question. It prints one command to run on the server:
|
|
44
58
|
|
|
45
59
|
```sh
|
|
46
60
|
agentgate init --name srv --always-on
|
|
47
|
-
agentgate join http://mac.<tailnet>.ts.net:7878 <code>
|
|
61
|
+
agentgate join http://mac.<tailnet>.ts.net:7878 <code> # Tailscale
|
|
62
|
+
agentgate join agr1.… # relay
|
|
48
63
|
agentgate setup
|
|
49
64
|
agentgate service install # also runs `loginctl enable-linger` so it survives logout/reboot
|
|
50
65
|
```
|
|
51
66
|
|
|
52
|
-
The server now has every account, MCP instance and repo mapping, and takes over token refreshes.
|
|
67
|
+
The server now has every account, MCP instance and repo mapping, and takes over token refreshes.
|
|
68
|
+
|
|
69
|
+
**The relay invite never expires and is a master key.** Anyone who has it can read every account and MCP login, so share it privately. If it leaks, run `agentgate relay rotate` and have every relay machine join again with the new command. Removing a relay machine (`agentgate unpair <node>` or **Remove** in the app) rotates the same way. A rotation can't revoke Tailscale links, so also unpair the removed machine on every machine you keep. By default it uses the hosted relay at `https://agentgate-relay.hanskristoffer.dk`. To use your own instead, deploy `apps/relay` to your Cloudflare account (see [operations](docs/operations.md#relay)) and pass `--relay-url`, or set `AGENTGATE_RELAY_URL`. `agentgate relay status` shows sync state and errors.
|
|
70
|
+
|
|
71
|
+
To control the server from the native app over Tailscale, open the connection settings at the bottom of the sidebar, enter `http://srv.<tailnet>.ts.net:7878`, and paste the token printed by `agentgate admin-token` on the server. Remote management uses bearer authentication over Tailscale. The relay carries sync only, not remote management.
|
|
53
72
|
|
|
54
73
|
## T3 Code
|
|
55
74
|
|
|
@@ -60,11 +79,11 @@ The server now has every account, MCP instance and repo mapping, and takes over
|
|
|
60
79
|
| Claude | `CLAUDE_CONFIG_DIR path` = `~/.config/agentgate/claude` |
|
|
61
80
|
| Codex | `CODEX_HOME path` = `~/.config/agentgate/codex` |
|
|
62
81
|
|
|
63
|
-
One instance per provider covers every account; the daemon switches accounts, so a thread never breaks when an account runs out.
|
|
82
|
+
One instance per provider covers every account; the daemon switches accounts, so a thread never breaks when an account runs out. In the app's **Accounts** screen, choose an **Active subscription** separately for Claude and Codex, or click **Use subscription** on an account. Your choice applies to the next request in every routed session and syncs to paired machines; if it is unavailable, the pool falls back to another account. Choose **Automatic** to clear the preference. The CLI equivalent is `agentgate accounts pin <id>` / `agentgate accounts unpin <id>`.
|
|
64
83
|
|
|
65
84
|
### Or: your normal Claude login
|
|
66
85
|
|
|
67
|
-
`agentgate setup --primary` adds `ANTHROPIC_BASE_URL` to `~/.claude/settings.json` and the agentgate MCP server to `~/.claude.json`, so the Claude Code you already use (and T3's default Claude instance) goes through agentgate while keeping its own login. Model requests use the pool; other requests keep your login, and your login is also the last resort when every pooled account is exhausted. Undo with `agentgate setup --primary off` (the previous base URL is restored, and later settings edits are preserved). It does the same for `~/.codex/config.toml` (or `$CODEX_HOME`): an `agentgate` model provider with `requires_openai_auth = true`, so Codex, the Codex app and T3's default Codex instance send their own ChatGPT login along as the last resort. Only do this with `agentgate service install`, or Claude Code and Codex can't reach their providers while the daemon is down.
|
|
86
|
+
`agentgate setup --primary` adds `ANTHROPIC_BASE_URL` to `~/.claude/settings.json` and the agentgate MCP server to `~/.claude.json`, so the Claude Code you already use (and T3's default Claude instance) goes through agentgate while keeping its own login. Claude Desktop is not affected: it sets its own API address; see [Claude Desktop](docs/claude-desktop.md). For only the MCP servers, use `agentgate setup --mcp`. Model requests use the pool; other requests keep your login, and your login is also the last resort when every pooled account is exhausted. Undo with `agentgate setup --primary off` (the previous base URL is restored, and later settings edits are preserved). It does the same for `~/.codex/config.toml` (or `$CODEX_HOME`): an `agentgate` model provider with `requires_openai_auth = true`, so Codex, the Codex app and T3's default Codex instance send their own ChatGPT login along as the last resort. Only do this with `agentgate service install`, or Claude Code and Codex can't reach their providers while the daemon is down.
|
|
68
87
|
|
|
69
88
|
## MCP servers per repo
|
|
70
89
|
|
|
@@ -86,15 +105,42 @@ agentgate mcp test posthog-lullu
|
|
|
86
105
|
|
|
87
106
|
The name is the tool prefix: in every repo mapped to `posthog-lullu` under the alias `posthog`, the agent sees `posthog__…` tools that reach that repo's PostHog project. The repo is taken from `git remote get-url origin` in the session's working directory (override with `AGENTGATE_PROJECT=owner/repo`). Mapping changes reach running sessions without a restart.
|
|
88
107
|
|
|
108
|
+
## Skills per repo
|
|
109
|
+
|
|
110
|
+
Skills are installed once and synced to every machine like MCP servers; you choose which repos use each one. In the native app (Skills), **Browse skills.sh** searches the [skills.sh](https://skills.sh) directory, **Add from source** uses the pinned `skills@1.7.0` CLI and accepts (`owner/repo`, `owner/repo@skill`, a Git or GitHub URL, a folder), and **New skill** writes a SKILL.md by hand. Then pick **Every session** or specific repos.
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
agentgate skills find postgres
|
|
114
|
+
agentgate skills add vercel-labs/agent-skills --skill web-design-guidelines --project Lullu-ai/lullu
|
|
115
|
+
agentgate skills add ./my-skill --project '*'
|
|
116
|
+
agentgate skills new release-notes --file SKILL.md
|
|
117
|
+
agentgate skills projects web-design-guidelines Lullu-ai/lullu other/repo
|
|
118
|
+
agentgate skills update # refetch every installed skill from its source
|
|
119
|
+
agentgate skills prepare . # wait for checkout links before launching an agent
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Fetching needs Node (`npx`) or Bun (`bunx`) on the daemon's machine; other machines get the files through sync. Each node writes skills to `~/.config/agentgate/skills/<name>` and only creates symlinks to them:
|
|
123
|
+
|
|
124
|
+
- **Every session**: the Claude and Codex folders `agentgate setup` writes (`~/.config/agentgate/{claude,codex}/skills`), plus `~/.claude/skills` and `~/.codex/skills` while `setup --primary` is on.
|
|
125
|
+
- **One repo**: `.claude/skills/<name>` in the main checkout (Claude Code falls back to it from worktrees) and `.agents/skills/<name>` in the main checkout and every worktree (Codex). The entries are added to `.git/info/exclude`.
|
|
126
|
+
|
|
127
|
+
Claude Code and Codex read skills before a session's MCP servers start, so repo links must exist ahead of time. A repo is known on a machine after its first agentgate session there, or after **Scan folder** in Projects; from then on its worktrees are watched and new ones are linked with bounded retries and independent periodic repair. Register or scan a checkout before launching its first session; watcher timing cannot guarantee first-session readiness. Changes apply to new sessions. Agentgate never replaces a folder it did not create: a name clash is listed under Skills → Skipped links. Skills run with your agent's permissions and are copied to every paired machine, so install only sources you trust; the app shows the skills.sh audit before installing.
|
|
128
|
+
|
|
129
|
+
The app installs the exact files shown in a preview. Previews expire after ten minutes or cache eviction; preview again to continue. Editing checks the saved revision and reports a conflict if another client or peer changed the skill. Skills → **Skills need attention** shows failed local materialization/link work, which the daemon retries automatically.
|
|
130
|
+
|
|
131
|
+
Bundles must contain a nonempty root `SKILL.md`, with unique portable paths and regular files. Symlinks and special files cannot be synced. Each bundle is limited to 3 MiB of base64 data (about 2.25 MiB of files) and 5,000 files; imports are limited to 100 skills and 24 MiB per pack. Large sources can be imported with `--skill` one skill at a time.
|
|
132
|
+
|
|
133
|
+
Repository-owned skills are mirrored only when you opt in under Projects → **Repository skill mirroring**. Mirroring creates relative links that can be reviewed and committed. Stopping mirroring stops future maintenance and leaves existing links in place; repository-owned links are preserved.
|
|
134
|
+
|
|
89
135
|
## Commands
|
|
90
136
|
|
|
91
|
-
Run `agentgate --help`. Useful ones: `status`, `accounts`, `accounts exhaust <id> [min]` (pretend an account hit its limit, for testing), `nodes`, `unpair <node>`, `export [--no-secrets]`, `import-backup <file>`, `service logs`.
|
|
137
|
+
Run `agentgate --help`. Useful ones: `status`, `accounts`, `accounts exhaust <id> [min]` (pretend an account hit its limit, for testing), `nodes`, `unpair <node>`, `relay status|reconcile|rotate|leave`, `export [--no-secrets]`, `import-backup <file>`, `service logs`.
|
|
92
138
|
|
|
93
139
|
## Things to know
|
|
94
140
|
|
|
95
141
|
- **Once imported, a login belongs to agentgate.** Don't keep using the original `~/.claude` or `~/.codex` login: its CLI would refresh the token and log agentgate out. `agentgate login` avoids this by using a throwaway directory.
|
|
96
|
-
- **Secrets are stored in plain text** in `~/.config/agentgate/agentgate.db` (mode 0600) and copied to every paired node. Pair only machines you control.
|
|
97
|
-
- **Terms of service.** Pool only your own accounts and keep a person driving the sessions;
|
|
142
|
+
- **Secrets are stored in plain text** in `~/.config/agentgate/agentgate.db` (mode 0600) and copied to every paired node. Pair only machines you control. The relay only ever sees them encrypted.
|
|
143
|
+
- **Terms of service.** Pool only your own accounts and keep a person driving the sessions; follow the providers’ applicable terms.
|
|
98
144
|
|
|
99
145
|
## Development
|
|
100
146
|
|
|
@@ -115,6 +161,7 @@ AGENTGATE_HOME=/tmp/ag AGENTGATE_PORT=7979 bun run cli -- init # a throwaway n
|
|
|
115
161
|
| `apps/agentgate` (`@agentgate/daemon`) | Bun daemon, standalone CLI, provider proxies, SQLite, sync, and MCP gateway |
|
|
116
162
|
| `apps/desktop` (`@agentgate/desktop`) | Tauri 2 shell with React/Vite, system appearance, translucent sidebar, and remembered window state |
|
|
117
163
|
| `apps/site` (`@agentgate/site`) | Static Astro landing page for Cloudflare Pages |
|
|
164
|
+
| `apps/relay` (`@agentgate/relay`) | Cloudflare Worker and Durable Objects for the encrypted sync relay |
|
|
118
165
|
| `packages/protocol` (`@agentgate/protocol`) | Shared control API types and configuration schemas |
|
|
119
166
|
|
|
120
167
|
The app uses Tauri commands to send HTTP requests from Rust. It has no browser HTTP fallback, server-rendered pages, cookies, or CORS management access. The daemon's `/api/*` management endpoints reject browser Origin/Fetch Metadata headers; remote requests require the node's admin bearer token. Status omits credentials, header values, command environments, and URL credentials/query strings. `/oauth/callback` is a small text response for MCP sign-in, including CLI sign-in. Provider and MCP traffic remains loopback-only. Backup export/restore and login-directory import require a local connection.
|
|
@@ -127,9 +174,9 @@ The app uses Tauri commands to send HTTP requests from Rust. It has no browser H
|
|
|
127
174
|
|
|
128
175
|
## Reliability
|
|
129
176
|
|
|
130
|
-
|
|
177
|
+
See [operations](docs/operations.md) for backup, upgrade, and live distribution checks. Account and MCP OAuth refreshes share holder coordination and a local cross-process lease. Running MCP shims reconnect after daemon restarts and update per-session mappings; tool calls with uncertain outcomes are never automatically replayed.
|
|
131
178
|
|
|
132
|
-
Nodes use **sync protocol
|
|
179
|
+
Nodes use **sync protocol 3** (update every paired machine together) and the app checks **management API version 1** when connecting. Deletion history is retained so offline machines cannot resurrect old configuration.
|
|
133
180
|
|
|
134
181
|
`export --no-secrets` / **Without secrets** produces an inventory: it omits logins, OAuth client secrets, and arbitrary MCP URLs, headers, commands/arguments, environment, fields, and secrets. Restored inventory transports need configuration again. Full exports contain working credentials and transport configuration.
|
|
135
182
|
|
|
@@ -157,7 +204,7 @@ bun scripts/smoke.ts dist/agentgate-darwin-arm64 # use your host target
|
|
|
157
204
|
bun scripts/codex-smoke.ts # optional: installed Codex CLI, fake upstream
|
|
158
205
|
```
|
|
159
206
|
|
|
160
|
-
Builds produce four macOS/Linux binaries and `dist/SHA256SUMS`. Releases use [release-please](https://github.com/googleapis/release-please): conventional commits on `main` (`feat:`, `fix:`) keep a release PR open with the next version and changelog, and merging it publishes the binaries to npm (`@hanskristoffer/agentpool` plus one `agentpool-<os>-<cpu>` package per binary, via `scripts/npm.ts`;
|
|
207
|
+
Builds produce four macOS/Linux binaries and `dist/SHA256SUMS`. Releases use [release-please](https://github.com/googleapis/release-please): conventional commits on `main` (`feat:`, `fix:`) keep a release PR open with the next version and changelog, and merging it publishes the binaries to npm (`@hanskristoffer/agentpool` plus one `agentpool-<os>-<cpu>` package per binary, via `scripts/npm.ts`; npm trusted publishing is configured for each generated package) and to a GitHub release. The installer verifies the checksum from the same resolved release before replacing an installed binary. CI runs tests, typechecking, frontend builds, and compiled CLI checks on macOS and Linux, plus Rust checks and app packaging on macOS. Releases also attach a universal macOS DMG, signed with a Developer ID certificate and notarized (`.github/workflows/build-macos.yml`; run it by hand with a tag to rebuild one). It needs these repository secrets:
|
|
161
208
|
|
|
162
209
|
| Secret | Value |
|
|
163
210
|
|---|---|
|
|
@@ -168,5 +215,11 @@ Builds produce four macOS/Linux binaries and `dist/SHA256SUMS`. Releases use [re
|
|
|
168
215
|
| `APPLE_API_KEY` | App Store Connect API key id |
|
|
169
216
|
| `APPLE_API_ISSUER` | its issuer id |
|
|
170
217
|
| `APPLE_API_KEY_CONTENT` | contents of the `.p8` |
|
|
218
|
+
| `TAURI_SIGNING_PRIVATE_KEY` | contents of the updater key from `bun run --filter @agentgate/desktop tauri signer generate` |
|
|
219
|
+
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | its password |
|
|
220
|
+
|
|
221
|
+
The release also carries a signed app archive and `latest.json`. Installed apps check that on launch and every four hours and offer a restart to update; the public key in `tauri.conf.json` rejects anything not signed with the updater key. Keep that key: without it, installed copies can never update again. On launch, an updated app also replaces the daemon copy the service runs when it differs from the bundled one, then restarts the service.
|
|
171
222
|
|
|
172
223
|
The bundled daemon is signed with the app's `Entitlements.plist`. It holds only `allow-jit`: under the hardened runtime, a compiled Bun binary without it falls back to the JavaScript interpreter and runs about 50 times slower. The standalone CLI binaries are not signed.
|
|
224
|
+
|
|
225
|
+
See [release and recovery instructions](docs/releasing.md).
|
package/package.json
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanskristoffer/agentpool",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/HansKristoffer/agentgate.git"
|
|
8
8
|
},
|
|
9
|
+
"homepage": "https://github.com/HansKristoffer/agentgate#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/HansKristoffer/agentgate/issues"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
9
19
|
"description": "Pools Claude and Codex subscriptions, hosts MCP servers per repo, and shares them between machines.",
|
|
10
20
|
"bin": {
|
|
11
21
|
"agentpool": "bin/agentpool.js",
|
|
12
22
|
"agentgate": "bin/agentpool.js"
|
|
13
23
|
},
|
|
14
24
|
"optionalDependencies": {
|
|
15
|
-
"agentpool-darwin-arm64": "0.
|
|
16
|
-
"agentpool-darwin-x64": "0.
|
|
17
|
-
"agentpool-linux-x64": "0.
|
|
18
|
-
"agentpool-linux-arm64": "0.
|
|
25
|
+
"agentpool-darwin-arm64": "0.6.0",
|
|
26
|
+
"agentpool-darwin-x64": "0.6.0",
|
|
27
|
+
"agentpool-linux-x64": "0.6.0",
|
|
28
|
+
"agentpool-linux-arm64": "0.6.0"
|
|
19
29
|
}
|
|
20
30
|
}
|