@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.
Files changed (2) hide show
  1. package/README.md +43 -42
  2. 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://github.com/anthropics/safehouse) 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).
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 into your working directory and edit it:
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` loads `./config.ts` from the current directory by default. Override the location with `GROUNDCREW_CONFIG=/path/to/config.ts`.
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 supported hosts. If Safehouse is unavailable and the model has a `sandbox` config, it uses persistent Docker Sandboxes. Set `models.isolation: "none"` only when you intentionally want direct, non-isolated execution.
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. **Run.** Doctor first, then a dry run, then the real thing:
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
- Or point at one or more allow-host files (groundcrew ships a starter file at `$(npm root -g)/@clipboard-health/groundcrew/clearance-allow-hosts`):
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
- Proxy output is written to `${XDG_CACHE_HOME:-$HOME/.cache}/clearance/clearance.log`, and the PID is written beside it as `clearance.pid`. Watch the proxy's `DENY` log lines and add only the domains your agents actually need.
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 a supported host, else Docker Sandboxes when the model has a sandbox config. Safehouse support or a model sandbox config is required; if neither is available, setup fails. Set `"none"` explicitly to run directly. |
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 supported hosts. When Safehouse is unavailable, 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.
132
- - **Safehouse uses clearance.** On hosts where `auto` resolves to Safehouse, groundcrew starts `clearance` when needed via `@clipboard-health/clearance`, then runs the `safehouse-clearance` wrapper shipped in that package, which loads the bundled `clearance.env` and appends `clearance-only.sb`. If a model command already starts with `safehouse`, groundcrew assumes that command owns its Safehouse flags and does not add the proxy profile a second time. To inspect blocked requests, run `tail -f "${XDG_CACHE_HOME:-$HOME/.cache}/clearance/clearance.log"`. To change the allowlist, set `CLEARANCE_ALLOW_HOSTS` (or `CLEARANCE_ALLOW_HOSTS_FILES`); if the proxy is already running, stop the PID in `clearance.pid` so the next launch can restart it with the new env.
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 externally promoted.** A PR open is the typical signal; whatever your Linear "in review" automation is, the orchestrator does not do that move itself.
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.0",
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.2",
41
- "@linear/sdk": "83.0.0",
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",