@clipboard-health/groundcrew 1.1.0 → 1.1.1
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 +43 -42
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -12,20 +12,21 @@ This installs the `crew` binary. `@clipboard-health/clearance` is pulled in tran
|
|
|
12
12
|
|
|
13
13
|
## Quickstart
|
|
14
14
|
|
|
15
|
-
1. **Install prereqs.** Node 24, `git`, `cmux` _or_ `tmux`, and the runtimes you actually want: Docker Sandboxes (`sbx`) for sandbox-backed agents, [Safehouse](https://
|
|
15
|
+
1. **Install prereqs.** Node 24, `git`, `cmux` _or_ `tmux`, and the runtimes you actually want: Docker Sandboxes (`sbx`) for sandbox-backed agents, [Safehouse](https://agent-safehouse.dev/) for macOS sandboxing, and the agent CLIs themselves (`claude`, `codex`, `cursor-agent`, ...). Optional: `codexbar` for session-usage gating. The `workspaceKind` config key picks the workspace backend (`auto` resolves to cmux when installed, else tmux).
|
|
16
16
|
|
|
17
17
|
2. **Create a Linear project to scope your work.** Any team works — make a project inside it and drop tickets in. The orchestrator polls by project, not by team, so you don't need a dedicated team.
|
|
18
18
|
|
|
19
|
-
3. **Create your config.** Copy the shipped example
|
|
19
|
+
3. **Create your config.** Copy the shipped example, edit it, and point `crew` at it via `GROUNDCREW_CONFIG`:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
cp "$(npm root -g)/@clipboard-health/groundcrew/configExample.ts" ./config.ts
|
|
23
23
|
$EDITOR ./config.ts
|
|
24
|
+
export GROUNDCREW_CONFIG="$PWD/config.ts"
|
|
24
25
|
```
|
|
25
26
|
|
|
26
27
|
At minimum set `linear.projectSlug` (paste the trailing segment of your Linear project URL, e.g. `ai-strategy-5152195762f3`), `workspace.projectDir`, and `workspace.knownRepositories`. Everything else has a default.
|
|
27
28
|
|
|
28
|
-
`crew`
|
|
29
|
+
`GROUNDCREW_CONFIG` is effectively required for npm-installed use. If it's unset, `crew` falls back to a `config.ts` sitting next to its own source files — only useful when running from a local checkout (see [Hacking on groundcrew](#hacking-on-groundcrew)).
|
|
29
30
|
|
|
30
31
|
4. **Provide a Linear API key.** `crew` expects `LINEAR_API_KEY` in its environment. Any mechanism works — shell export, [direnv](https://direnv.net/), a `.env` file you `source`, or piping through `op run` if you store the credential in 1Password:
|
|
31
32
|
|
|
@@ -39,7 +40,7 @@ This installs the `crew` binary. `@clipboard-health/clearance` is pulled in tran
|
|
|
39
40
|
op run --env-file .env.1password -- crew doctor
|
|
40
41
|
```
|
|
41
42
|
|
|
42
|
-
5. **Prepare isolation and agent auth.** With `models.isolation: "auto"`, groundcrew prefers Safehouse on
|
|
43
|
+
5. **Prepare isolation and agent auth.** With `models.isolation: "auto"`, groundcrew prefers Safehouse on macOS. On non-macOS hosts, it falls back to persistent Docker Sandboxes if the model has a `sandbox` config. Set `models.isolation: "none"` only when you intentionally want direct, non-isolated execution.
|
|
43
44
|
|
|
44
45
|
If you use Docker Sandboxes, start the daemon and log in before `crew run`:
|
|
45
46
|
|
|
@@ -60,58 +61,58 @@ This installs the `crew` binary. `@clipboard-health/clearance` is pulled in tran
|
|
|
60
61
|
crew sandbox auth <repo> --model codex
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
6. **
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
crew doctor
|
|
67
|
-
crew run --dry-run
|
|
68
|
-
crew run # one-shot
|
|
69
|
-
crew run --watch # poll forever
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
When groundcrew resolves a model to the `safehouse` isolation strategy, it calls `ensureClearance` from `@clipboard-health/clearance` to start `clearance` on `http://127.0.0.1:19999` if nothing is already listening, then launches the agent through the bundled `safehouse-clearance` wrapper. The default allowlist covers model APIs, Linear, Notion, Slack, and Datadog. Override it before starting groundcrew:
|
|
64
|
+
6. **Set the clearance allowlist (Safehouse only).** When the resolved isolation strategy is Safehouse, groundcrew starts `clearance` from `@clipboard-health/clearance` on `http://127.0.0.1:19999` (skipping the launch if something is already listening) and runs the agent through the bundled `safehouse-clearance` wrapper. Clearance refuses to start without an allowlist — see [its README](../clearance/README.md) for the proxy's env vars, log paths, and DNS rules. The shortest path is to set the env before `crew run`:
|
|
73
65
|
|
|
74
66
|
```bash
|
|
75
67
|
CLEARANCE_ALLOW_HOSTS="api.openai.com,auth.openai.com,api.anthropic.com,mcp.linear.app,api.linear.app" \
|
|
76
68
|
crew run --watch
|
|
77
69
|
```
|
|
78
70
|
|
|
79
|
-
|
|
71
|
+
Groundcrew also ships a starter allowlist file covering model APIs, Linear, Notion, Slack, Datadog, GitHub, npm, and common dev tooling at `$(npm root -g)/@clipboard-health/groundcrew/clearance-allow-hosts`. Point clearance at it (and optionally a personal file) via `CLEARANCE_ALLOW_HOSTS_FILES`:
|
|
80
72
|
|
|
81
73
|
```bash
|
|
82
74
|
CLEARANCE_ALLOW_HOSTS_FILES="$(npm root -g)/@clipboard-health/groundcrew/clearance-allow-hosts:$HOME/.config/clearance/personal-allow-hosts" \
|
|
83
75
|
crew run --watch
|
|
84
76
|
```
|
|
85
77
|
|
|
86
|
-
|
|
78
|
+
Watch `${XDG_CACHE_HOME:-$HOME/.cache}/clearance/clearance.log` for `DENY` lines and add only the domains your agents actually need.
|
|
79
|
+
|
|
80
|
+
7. **Run.** Doctor first, then a dry run, then the real thing:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
crew doctor
|
|
84
|
+
crew run --dry-run
|
|
85
|
+
crew run # one-shot
|
|
86
|
+
crew run --watch # poll forever
|
|
87
|
+
```
|
|
87
88
|
|
|
88
89
|
## Config reference
|
|
89
90
|
|
|
90
91
|
Required fields are marked **required**; everything else has a default and can be omitted from `config.ts`.
|
|
91
92
|
|
|
92
|
-
| Key | Default | What it does
|
|
93
|
-
| --------------------------------------- | ------------------- |
|
|
94
|
-
| `linear.projectSlug` | **required** | Linear project URL slug (e.g. `ai-strategy-5152195762f3`). The trailing 12-char hex `slugId` is what's matched against Linear's API; the leading name keeps `config.ts` self-documenting and the lookup survives project renames.
|
|
95
|
-
| `linear.statuses.todo` | `"Todo"` | Status name picked up for new work.
|
|
96
|
-
| `linear.statuses.inProgress` | `"In Progress"` | Status set after a workspace is provisioned; counts toward `maximumInProgress`.
|
|
97
|
-
| `linear.statuses.done` | `"Done"` | Status that triggers worktree cleanup.
|
|
98
|
-
| `linear.statuses.terminal` | `["Done"]` | Additional status names treated as terminal for cleanup, board remaining counts, and blocker checks. The `done` status is always included.
|
|
99
|
-
| `git.remote` | `"origin"` | Remote used for `fetch` and as the worktree base ref.
|
|
100
|
-
| `git.defaultBranch` | `"main"` | Branch fetched from `git.remote` and used as the worktree base.
|
|
101
|
-
| `workspace.projectDir` | **required** | Parent dir for cloned repos. `$PROJECT_DIR` env var overrides. Sandbox-backed ticket worktrees live under each repo's `.sbx/` directory.
|
|
102
|
-
| `workspace.knownRepositories` | **required** | Repos searched for in ticket descriptions to infer where work belongs. Tickets fail fast when no known repo appears.
|
|
103
|
-
| `orchestrator.maximumInProgress` | `4` | Cap on tickets in `linear.statuses.inProgress` at once.
|
|
104
|
-
| `orchestrator.pollIntervalMilliseconds` | `120_000` | Poll interval in `--watch` mode.
|
|
105
|
-
| `orchestrator.sessionLimitPercentage` | `85` | Number in `(0, 100]`. A model whose codexbar session window exceeds this percentage is skipped that tick.
|
|
106
|
-
| `models.default` | `"claude"` | Agent used when a ticket has no agent label. Must exist in `models.definitions`.
|
|
107
|
-
| `models.isolation` | `"auto"` | Isolation strategy. `"auto"` picks Safehouse on
|
|
108
|
-
| `models.definitions` | `{ claude, codex }` | Agent definitions. Additive merge with shipped defaults.
|
|
109
|
-
| `models.definitions.<name>.cmd` | — | Shell command launched for the model. For sandbox-backed models this runs inside the persistent sandbox; otherwise it runs in the workspace. `{{worktree}}` and `{{sandbox}}` are replaced before launch.
|
|
110
|
-
| `models.definitions.<name>.color` | — | Color for the workspace status pill (cmux only; tmux silently drops it).
|
|
111
|
-
| `models.definitions.<name>.sandbox` | `{ agent }` | Optional Docker Sandboxes backing. Defaults set `claude` → `agent: "claude"` and `codex` → `agent: "codex"`. Set `sandbox: false` on an override to run the command outside Docker Sandboxes.
|
|
112
|
-
| `models.definitions.<name>.usage` | optional | If set, codexbar usage is fetched for this model and gated by `sessionLimitPercentage`. Omit to never gate. When `usage.codexbar.source` is omitted, groundcrew uses `auto` on macOS and `cli` elsewhere.
|
|
113
|
-
| `prompts.initial` | (template) | First message sent to the agent. Placeholders: `{{ticket}}`, `{{worktree}}`, `{{title}}`, `{{description}}`.
|
|
114
|
-
| `workspaceKind` | `"auto"` | Terminal session manager. `"auto"` picks `cmux` when on PATH, else `tmux`. Set to `"cmux"` or `"tmux"` to fail loudly when the chosen backend is missing. tmux windows live in a dedicated `groundcrew` session.
|
|
93
|
+
| Key | Default | What it does |
|
|
94
|
+
| --------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
95
|
+
| `linear.projectSlug` | **required** | Linear project URL slug (e.g. `ai-strategy-5152195762f3`). The trailing 12-char hex `slugId` is what's matched against Linear's API; the leading name keeps `config.ts` self-documenting and the lookup survives project renames. |
|
|
96
|
+
| `linear.statuses.todo` | `"Todo"` | Status name picked up for new work. |
|
|
97
|
+
| `linear.statuses.inProgress` | `"In Progress"` | Status set after a workspace is provisioned; counts toward `maximumInProgress`. |
|
|
98
|
+
| `linear.statuses.done` | `"Done"` | Status that triggers worktree cleanup. |
|
|
99
|
+
| `linear.statuses.terminal` | `["Done"]` | Additional status names treated as terminal for cleanup, board remaining counts, and blocker checks. The `done` status is always included. |
|
|
100
|
+
| `git.remote` | `"origin"` | Remote used for `fetch` and as the worktree base ref. |
|
|
101
|
+
| `git.defaultBranch` | `"main"` | Branch fetched from `git.remote` and used as the worktree base. |
|
|
102
|
+
| `workspace.projectDir` | **required** | Parent dir for cloned repos. `$PROJECT_DIR` env var overrides. Sandbox-backed ticket worktrees live under each repo's `.sbx/` directory. |
|
|
103
|
+
| `workspace.knownRepositories` | **required** | Repos searched for in ticket descriptions to infer where work belongs. Tickets fail fast when no known repo appears. |
|
|
104
|
+
| `orchestrator.maximumInProgress` | `4` | Cap on tickets in `linear.statuses.inProgress` at once. |
|
|
105
|
+
| `orchestrator.pollIntervalMilliseconds` | `120_000` | Poll interval in `--watch` mode. |
|
|
106
|
+
| `orchestrator.sessionLimitPercentage` | `85` | Number in `(0, 100]`. A model whose codexbar session window exceeds this percentage is skipped that tick. |
|
|
107
|
+
| `models.default` | `"claude"` | Agent used when a ticket has no agent label. Must exist in `models.definitions`. |
|
|
108
|
+
| `models.isolation` | `"auto"` | Isolation strategy. `"auto"` picks Safehouse on macOS, else Docker Sandboxes when the model has a sandbox config. Safehouse or a model sandbox config is required; if neither is available, setup fails. Set `"none"` explicitly to run directly. |
|
|
109
|
+
| `models.definitions` | `{ claude, codex }` | Agent definitions. Additive merge with shipped defaults. |
|
|
110
|
+
| `models.definitions.<name>.cmd` | — | Shell command launched for the model. For sandbox-backed models this runs inside the persistent sandbox; otherwise it runs in the workspace. `{{worktree}}` and `{{sandbox}}` are replaced before launch. |
|
|
111
|
+
| `models.definitions.<name>.color` | — | Color for the workspace status pill (cmux only; tmux silently drops it). |
|
|
112
|
+
| `models.definitions.<name>.sandbox` | `{ agent }` | Optional Docker Sandboxes backing. Defaults set `claude` → `agent: "claude"` and `codex` → `agent: "codex"`. Set `sandbox: false` on an override to run the command outside Docker Sandboxes. |
|
|
113
|
+
| `models.definitions.<name>.usage` | optional | If set, codexbar usage is fetched for this model and gated by `sessionLimitPercentage`. Omit to never gate. When `usage.codexbar.source` is omitted, groundcrew uses `auto` on macOS and `cli` elsewhere. |
|
|
114
|
+
| `prompts.initial` | (template) | First message sent to the agent. Placeholders: `{{ticket}}`, `{{worktree}}`, `{{title}}`, `{{description}}`. |
|
|
115
|
+
| `workspaceKind` | `"auto"` | Terminal session manager. `"auto"` picks `cmux` when on PATH, else `tmux`. Set to `"cmux"` or `"tmux"` to fail loudly when the chosen backend is missing. tmux windows live in a dedicated `groundcrew` session. |
|
|
115
116
|
|
|
116
117
|
The branch prefix (`<prefix>-<TICKET>`) is derived from your OS username (`os.userInfo().username`), not configured. Agent selection looks for a top-level Linear label named `agent-<model>` (e.g. `agent-claude`, `agent-codex`). The reserved label `agent-any` routes the ticket to the configured model with the most available session capacity (lowest codexbar session-used percent), skipping any model already over `sessionLimitPercentage`. With no usage data, `agent-any` resolves to `models.default`. The name `any` cannot be used in `models.definitions`. Todo tickets blocked by Linear issues that are not in `linear.statuses.terminal` are skipped until their blockers reach a terminal status.
|
|
117
118
|
|
|
@@ -128,14 +129,14 @@ crew cleanup <TICKET>
|
|
|
128
129
|
|
|
129
130
|
## Gotchas
|
|
130
131
|
|
|
131
|
-
- **Auto isolation prefers Safehouse.** The shipped `models.isolation: "auto"` uses Safehouse on
|
|
132
|
-
- **Safehouse
|
|
132
|
+
- **Auto isolation prefers Safehouse.** The shipped `models.isolation: "auto"` uses Safehouse on macOS. On non-macOS hosts (Linux/WSL), shipped models with Docker Sandbox config use a persistent sandbox per repo/model, named `groundcrew-<repo>-<model>`. `crew run --ticket` creates per-ticket `sbx --branch` worktrees inside that sandbox and launches the task with `sbx exec`, so `npm clean-install` and the agent both run inside Docker.
|
|
133
|
+
- **Safehouse-already-wrapped commands are not re-wrapped.** If a `models.definitions.<name>.cmd` already starts with `safehouse`, groundcrew assumes that command owns its Safehouse flags and does not add the `safehouse-clearance` wrapper a second time. Changing the proxy's allowlist after it's running requires killing the PID in `${XDG_CACHE_HOME:-$HOME/.cache}/clearance/clearance.pid` so the next launch picks up the new env.
|
|
133
134
|
- **Authenticate before first ticket setup.** Run `crew sandbox auth <repo> --model <name>` before `crew run` for a repo/model. That first run carries no ticket prompt, so a required OAuth `/login` cannot consume task context.
|
|
134
135
|
- **Sandbox cleanup is intentionally conservative.** `crew cleanup` removes the per-ticket worktree and branch, but keeps the persistent sandbox so OAuth sessions, installed packages, and agent config survive later tickets. Use `sbx ls` and `sbx rm --force <name>` when you intentionally want to delete that persisted sandbox state.
|
|
135
136
|
- **Usage source defaults are OS-aware.** `codexbar` usage uses `--source auto` on macOS so CodexBar can prefer account/web sources and fall back as it supports. On Linux/WSL it uses `--source cli`, so install the CodexBar Linux CLI and authenticate the provider CLIs inside that environment.
|
|
136
137
|
- **Status names matter.** If your team uses `Started` instead of `In Progress`, set `linear.statuses.inProgress = "Started"`.
|
|
137
138
|
- **Leaf-only.** Parent issues with children are ignored — sub-issues are the work items.
|
|
138
|
-
- **Tickets stay in the in-progress status until
|
|
139
|
+
- **Tickets stay in the in-progress status until something else moves them.** Groundcrew sets a ticket to `inProgress` when it provisions a workspace and never advances it. The next transition (typically "in review" when a PR opens) is left to your team's Linear automation rules.
|
|
139
140
|
- **Project must be on a single Linear team in practice.** Cross-team projects work — the orchestrator caches the in-progress state ID per team — but every team in the project must use the same status name for `linear.statuses.inProgress`.
|
|
140
141
|
- **Doctor's command introspection is shallow.** For sandbox-backed models it checks `sbx` plus `sbx diagnose`. For non-sandbox models it tokenizes `cmd` and checks the first two non-flag tokens against PATH (so `safehouse claude --foo` checks both `safehouse` and `claude`). Boolean flags without values, env-var assignments (`FOO=1`), shell pipelines, and subshells are not parsed — verify those manually. In particular, `npx -y claude` and `env FOO=1 claude` only check the wrapper, not the wrapped CLI.
|
|
141
142
|
- **Agent CLI must accept a positional prompt.** The handoff is `<your cmd> "<prompt>"`. `claude`, `codex`, and `cursor-agent` all support this.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/groundcrew",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Linear-driven orchestrator that launches AI coding agents in isolated git worktrees, with workspace lifecycle, sandbox auth, and usage tracking.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@clipboard-health/clearance": "1.0.
|
|
41
|
-
"@linear/sdk": "
|
|
40
|
+
"@clipboard-health/clearance": "1.0.3",
|
|
41
|
+
"@linear/sdk": "84.0.0",
|
|
42
42
|
"tslib": "2.8.1"
|
|
43
43
|
},
|
|
44
44
|
"types": "./src/index.d.ts",
|