@clipboard-health/groundcrew 4.35.1 → 4.36.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 +6 -1
- package/crew.config.example.ts +15 -4
- package/dist/commands/resumeWorkspace.d.ts.map +1 -1
- package/dist/commands/resumeWorkspace.js +2 -1
- package/dist/commands/setupWorkspace.d.ts.map +1 -1
- package/dist/commands/setupWorkspace.js +2 -1
- package/dist/lib/agentLaunch.d.ts +3 -0
- package/dist/lib/agentLaunch.d.ts.map +1 -1
- package/dist/lib/agentLaunch.js +33 -5
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +18 -4
- package/dist/lib/launchCommand.d.ts +12 -0
- package/dist/lib/launchCommand.d.ts.map +1 -1
- package/dist/lib/launchCommand.js +13 -4
- package/docs/adr/0002-one-task-source-path-linear-is-an-adapter.md +2 -2
- package/docs/commands.md +4 -4
- package/docs/configuration.md +33 -6
- package/docs/task-sources.md +5 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -69,10 +69,15 @@ crew run --watch
|
|
|
69
69
|
|
|
70
70
|
Linear works out of the box: assign tasks to yourself and add an `agent-*` label.
|
|
71
71
|
|
|
72
|
-
- `agent-claude`, `agent-codex`, or `agent-<name>` routes to that
|
|
72
|
+
- `agent-claude`, `agent-codex`, or `agent-<name>` routes to that enabled launch profile.
|
|
73
73
|
- `agent-any` routes to the enabled agent with the most session headroom, after skipping agents over their session limit or weekly paced budget.
|
|
74
74
|
- Tasks without an `agent-*` label are ignored by `crew run`; dispatch one manually with `crew start <TASK>`.
|
|
75
75
|
|
|
76
|
+
Agent names are launch profiles, so you can use them to pick model tiers. For example,
|
|
77
|
+
define `claude-fable` with `claude --model claude-fable-5 --permission-mode auto`
|
|
78
|
+
and `claude-opus` with `claude --model claude-opus-4-8 --permission-mode auto`,
|
|
79
|
+
then label tasks with `agent-claude-fable` or `agent-claude-opus`.
|
|
80
|
+
|
|
76
81
|
Groundcrew scans `workspace.knownRepositories` to infer which repo a task belongs to.
|
|
77
82
|
|
|
78
83
|
A task blocked by non-terminal blockers is skipped until those blockers are done.
|
package/crew.config.example.ts
CHANGED
|
@@ -52,13 +52,24 @@ export default {
|
|
|
52
52
|
},
|
|
53
53
|
agents: {
|
|
54
54
|
default: "claude",
|
|
55
|
-
// `definitions` is the enabled
|
|
56
|
-
// opt into the shipped command/color/usage preset. Add
|
|
57
|
-
// want both shipped agents
|
|
58
|
-
// `
|
|
55
|
+
// `definitions` is the enabled launch profile set. Built-in keys can use
|
|
56
|
+
// `{}` to opt into the shipped command/color/usage preset. Add
|
|
57
|
+
// `codex: {}` if you want both shipped agents. Agent names are launch
|
|
58
|
+
// profiles: add custom entries such as `claude-fable` or `claude-opus` to
|
|
59
|
+
// pin a model per task, then tag tasks with `agent-<name>`.
|
|
59
60
|
definitions: {
|
|
60
61
|
claude: {},
|
|
61
62
|
// codex: {},
|
|
63
|
+
// "claude-fable": {
|
|
64
|
+
// cmd: "claude --model claude-fable-5 --permission-mode auto",
|
|
65
|
+
// color: "#C15F3C",
|
|
66
|
+
// usage: { codexbar: { provider: "claude" } },
|
|
67
|
+
// },
|
|
68
|
+
// "claude-opus": {
|
|
69
|
+
// cmd: "claude --model claude-opus-4-8 --permission-mode auto",
|
|
70
|
+
// color: "#8A4FFF",
|
|
71
|
+
// usage: { codexbar: { provider: "claude" } },
|
|
72
|
+
// },
|
|
62
73
|
// cursor: {
|
|
63
74
|
// cmd: "cursor-agent",
|
|
64
75
|
// color: "#929292",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAenE,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AA0ID,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"resumeWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/resumeWorkspace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAenE,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AA0ID,wBAAsB,eAAe,CACnC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtE"}
|
|
@@ -119,7 +119,7 @@ export async function resumeWorkspace(config, options) {
|
|
|
119
119
|
if (definition === undefined) {
|
|
120
120
|
throw new Error(`Unknown agent: ${context.agent}`);
|
|
121
121
|
}
|
|
122
|
-
const { runner, sandboxName, ensureReady } = await prepareAgentLaunch({
|
|
122
|
+
const { runner, sandboxName, workspaceKind, ensureReady } = await prepareAgentLaunch({
|
|
123
123
|
config,
|
|
124
124
|
agent: context.agent,
|
|
125
125
|
definition,
|
|
@@ -150,6 +150,7 @@ export async function resumeWorkspace(config, options) {
|
|
|
150
150
|
workingDir: launchDir,
|
|
151
151
|
secretsFile,
|
|
152
152
|
sandboxName,
|
|
153
|
+
workspaceKind,
|
|
153
154
|
workerEnvironment: workerEnvironmentForTask(context.completionTaskId),
|
|
154
155
|
}));
|
|
155
156
|
const launchCmd = stageWorkspaceLaunchCommand(stagedPrompt.directory, launchCommand);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAuBnE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAuBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAuBnE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAuBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CA+Hf;AAgJD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
|
|
@@ -32,7 +32,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
|
|
|
32
32
|
if (!definition) {
|
|
33
33
|
throw new Error(`Unknown agent: ${agent}`);
|
|
34
34
|
}
|
|
35
|
-
const { runner, sandboxName, ensureReady } = await prepareAgentLaunch({
|
|
35
|
+
const { runner, sandboxName, workspaceKind, ensureReady } = await prepareAgentLaunch({
|
|
36
36
|
config,
|
|
37
37
|
agent,
|
|
38
38
|
definition,
|
|
@@ -92,6 +92,7 @@ export async function setupWorkspace(config, options, runOptions = {}) {
|
|
|
92
92
|
secretsFile,
|
|
93
93
|
prepareWorktreeCommand,
|
|
94
94
|
sandboxName,
|
|
95
|
+
workspaceKind,
|
|
95
96
|
workerEnvironment: workerEnvironmentForTask(completionTaskId),
|
|
96
97
|
});
|
|
97
98
|
srtSettingsDir = stagedSrtSettingsDir;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type LocalRunner, type AgentDefinition, type ResolvedConfig } from "./config.ts";
|
|
2
2
|
import { type WorkerEnvironment } from "./launchCommand.ts";
|
|
3
|
+
import type { WorkspaceKind } from "./workspaceAdapter.ts";
|
|
3
4
|
/**
|
|
4
5
|
* Stage any srt settings and build the workspace launch command — the assembly
|
|
5
6
|
* shared verbatim by `setupWorkspace` (fresh runs) and `resumeWorkspace`
|
|
@@ -17,6 +18,7 @@ export declare function composeAgentLaunch(input: {
|
|
|
17
18
|
secretsFile?: string | undefined;
|
|
18
19
|
prepareWorktreeCommand?: string | undefined;
|
|
19
20
|
sandboxName?: string | undefined;
|
|
21
|
+
workspaceKind: WorkspaceKind;
|
|
20
22
|
workerEnvironment?: WorkerEnvironment | undefined;
|
|
21
23
|
}): {
|
|
22
24
|
launchCommand: string;
|
|
@@ -25,6 +27,7 @@ export declare function composeAgentLaunch(input: {
|
|
|
25
27
|
interface PreparedAgentLaunch {
|
|
26
28
|
runner: LocalRunner;
|
|
27
29
|
sandboxName: string | undefined;
|
|
30
|
+
workspaceKind: WorkspaceKind;
|
|
28
31
|
ensureReady: () => Promise<void>;
|
|
29
32
|
}
|
|
30
33
|
export declare function prepareAgentLaunch(input: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentLaunch.d.ts","sourceRoot":"","sources":["../../src/lib/agentLaunch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agentLaunch.d.ts","sourceRoot":"","sources":["../../src/lib/agentLaunch.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AAErB,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAM5B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACnD,GAAG;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAgChE;AAmDD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAsD/B;AAwBD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB"}
|
package/dist/lib/agentLaunch.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { ensureClearance } from "@clipboard-health/clearance";
|
|
1
|
+
import { ensureClearance, resolveSafehouseCmuxIntegration, safehouseCmuxIntegrationWarningLines, } from "@clipboard-health/clearance";
|
|
2
2
|
import { clearanceAllowHostsFilesFromEnvironment } from "./clearanceAllowlist.js";
|
|
3
3
|
import { hasPreLaunchEnv, } from "./config.js";
|
|
4
4
|
import { detectHostCapabilities } from "./host.js";
|
|
5
|
-
import { buildLaunchCommand } from "./launchCommand.js";
|
|
5
|
+
import { buildLaunchCommand, inferAgentCommandName, } from "./launchCommand.js";
|
|
6
6
|
import { assertLocalRunnerRequirements, resolveLocalRunner } from "./localRunner.js";
|
|
7
7
|
import { sandboxNameFor } from "./sandboxName.js";
|
|
8
8
|
import { buildAndStageSrtLaunch, resolveGitCommonDir } from "./srtLaunch.js";
|
|
9
|
-
import { debug, sleep } from "./util.js";
|
|
10
|
-
import { workspaces } from "./workspaces.js";
|
|
9
|
+
import { debug, sleep, writeError } from "./util.js";
|
|
10
|
+
import { resolveWorkspaceKind, workspaces } from "./workspaces.js";
|
|
11
11
|
/**
|
|
12
12
|
* Stage any srt settings and build the workspace launch command — the assembly
|
|
13
13
|
* shared verbatim by `setupWorkspace` (fresh runs) and `resumeWorkspace`
|
|
@@ -23,6 +23,9 @@ export function composeAgentLaunch(input) {
|
|
|
23
23
|
definition: input.definition,
|
|
24
24
|
})
|
|
25
25
|
: undefined;
|
|
26
|
+
const safehouseAgentIntegration = input.runner === "safehouse"
|
|
27
|
+
? safehouseAgentIntegrationFor(input.workspaceKind, input.definition)
|
|
28
|
+
: undefined;
|
|
26
29
|
const launchCommand = buildLaunchCommand({
|
|
27
30
|
definition: input.definition,
|
|
28
31
|
promptFile: input.promptFile,
|
|
@@ -38,6 +41,7 @@ export function composeAgentLaunch(input) {
|
|
|
38
41
|
srtAgentConfigDirEnv: staged?.agentConfigDirEnv,
|
|
39
42
|
workerEnvironment: input.workerEnvironment,
|
|
40
43
|
safehouseAddDirs: input.runner === "safehouse" ? resolveSafehouseAddDirs(input.worktreeDir) : undefined,
|
|
44
|
+
safehouseAgentIntegration,
|
|
41
45
|
});
|
|
42
46
|
return { launchCommand, srtSettingsDir: staged?.directory };
|
|
43
47
|
}
|
|
@@ -60,9 +64,33 @@ export function composeAgentLaunch(input) {
|
|
|
60
64
|
function resolveSafehouseAddDirs(worktreeDir) {
|
|
61
65
|
return [...new Set([worktreeDir, resolveGitCommonDir(worktreeDir)])];
|
|
62
66
|
}
|
|
67
|
+
function safehouseAgentIntegrationFor(workspaceKind, definition) {
|
|
68
|
+
if (workspaceKind !== "cmux") {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const isClaudeAgent = inferAgentCommandName(definition.cmd) === "claude";
|
|
72
|
+
const cmuxIntegration = resolveSafehouseCmuxIntegration();
|
|
73
|
+
if (isClaudeAgent) {
|
|
74
|
+
warnOnCmuxIntegrationDrift({ unreviewedEnvNames: cmuxIntegration.unreviewedEnvNames });
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
addDirsReadOnly: cmuxIntegration.addDirsReadOnly,
|
|
78
|
+
envPass: cmuxIntegration.envPass,
|
|
79
|
+
commandPreludes: isClaudeAgent ? [cmuxIntegration.claudeCommandPrelude] : [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function warnOnCmuxIntegrationDrift(input) {
|
|
83
|
+
for (const warningLine of safehouseCmuxIntegrationWarningLines({
|
|
84
|
+
commandName: "groundcrew",
|
|
85
|
+
unreviewedEnvNames: input.unreviewedEnvNames,
|
|
86
|
+
})) {
|
|
87
|
+
writeError(warningLine);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
63
90
|
export async function prepareAgentLaunch(input) {
|
|
64
91
|
const host = await detectHostCapabilities(input.signal);
|
|
65
92
|
const runner = resolveLocalRunner(input.config.local.runner, host);
|
|
93
|
+
const workspaceKind = resolveWorkspaceKind({ config: input.config, host }).resolved;
|
|
66
94
|
assertLocalRunnerRequirements(host, runner);
|
|
67
95
|
const ensureReady = runner === "safehouse"
|
|
68
96
|
? async () => {
|
|
@@ -96,7 +124,7 @@ export async function prepareAgentLaunch(input) {
|
|
|
96
124
|
const sandboxName = runner === "sdx" && input.definition.sandbox !== undefined
|
|
97
125
|
? sandboxNameFor({ agent: input.definition.sandbox.agent })
|
|
98
126
|
: undefined;
|
|
99
|
-
return { runner, sandboxName, ensureReady };
|
|
127
|
+
return { runner, sandboxName, workspaceKind, ensureReady };
|
|
100
128
|
}
|
|
101
129
|
async function alreadyReady() {
|
|
102
130
|
await Promise.resolve();
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.js
CHANGED
|
@@ -120,11 +120,19 @@ const ALLOWED_PROMPT_PLACEHOLDERS = new Set([
|
|
|
120
120
|
const PROMPT_PLACEHOLDER_RE = /{{[^{}]*}}/g;
|
|
121
121
|
const PERCENT_MIN_EXCLUSIVE = 0;
|
|
122
122
|
const PERCENT_MAX = 100;
|
|
123
|
+
const CONFIG_ERROR_PREFIX = "groundcrew config: ";
|
|
123
124
|
function defaultLogFile() {
|
|
124
125
|
return xdgStatePath("groundcrew", "groundcrew.log");
|
|
125
126
|
}
|
|
126
127
|
function fail(message) {
|
|
127
|
-
throw new Error(
|
|
128
|
+
throw new Error(`${CONFIG_ERROR_PREFIX}${message}`);
|
|
129
|
+
}
|
|
130
|
+
function rethrowWithConfigPath({ error, filepath }) {
|
|
131
|
+
if (error instanceof Error && error.message.startsWith(CONFIG_ERROR_PREFIX)) {
|
|
132
|
+
const message = error.message.slice(CONFIG_ERROR_PREFIX.length);
|
|
133
|
+
throw new Error(`${CONFIG_ERROR_PREFIX}${filepath}: ${message}`, { cause: error });
|
|
134
|
+
}
|
|
135
|
+
throw error;
|
|
128
136
|
}
|
|
129
137
|
function isNonEmptyString(value) {
|
|
130
138
|
return typeof value === "string" && value.length > 0;
|
|
@@ -792,9 +800,15 @@ export async function loadConfigWithSource() {
|
|
|
792
800
|
fail(`${filepath} must export a config object (e.g. \`export default { ... } satisfies Config\`)`);
|
|
793
801
|
}
|
|
794
802
|
debug(`Loaded config from ${filepath}`);
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
803
|
+
let resolved;
|
|
804
|
+
try {
|
|
805
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- runtime fields are validated by applyDefaults/validate
|
|
806
|
+
resolved = applyDefaults(userConfig, path.dirname(filepath));
|
|
807
|
+
validate(resolved);
|
|
808
|
+
}
|
|
809
|
+
catch (error) {
|
|
810
|
+
rethrowWithConfigPath({ error, filepath });
|
|
811
|
+
}
|
|
798
812
|
setLogFile(resolved.logging.file);
|
|
799
813
|
cached = Object.freeze({
|
|
800
814
|
config: Object.freeze(resolved),
|
|
@@ -41,6 +41,11 @@ declare const WORKER_ENVIRONMENT_NAMES: readonly ["GROUNDCREW_TASK_ID", "GROUNDC
|
|
|
41
41
|
type WorkerEnvironmentName = (typeof WORKER_ENVIRONMENT_NAMES)[number];
|
|
42
42
|
export type WorkerEnvironment = Readonly<Record<WorkerEnvironmentName, string>>;
|
|
43
43
|
export declare function workerEnvironmentForTask(taskId: string): WorkerEnvironment;
|
|
44
|
+
export interface SafehouseAgentIntegration {
|
|
45
|
+
addDirsReadOnly: readonly string[];
|
|
46
|
+
envPass: readonly string[];
|
|
47
|
+
commandPreludes: readonly string[];
|
|
48
|
+
}
|
|
44
49
|
interface LaunchCommandArguments {
|
|
45
50
|
definition: AgentDefinition;
|
|
46
51
|
promptFile: string;
|
|
@@ -115,6 +120,13 @@ interface LaunchCommandArguments {
|
|
|
115
120
|
* pre-existing behavior). Only consumed by the safehouse wrap.
|
|
116
121
|
*/
|
|
117
122
|
safehouseAddDirs?: readonly string[] | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Extra host-terminal integration surface granted only to the Safehouse agent
|
|
125
|
+
* wrap. The agent may need to execute host shims and reach their sockets
|
|
126
|
+
* while repo-controlled prepareWorktree hooks should not inherit those paths
|
|
127
|
+
* or env vars.
|
|
128
|
+
*/
|
|
129
|
+
safehouseAgentIntegration?: SafehouseAgentIntegration | undefined;
|
|
118
130
|
/**
|
|
119
131
|
* Groundcrew-managed task metadata exposed to the launched worker. Forwarded
|
|
120
132
|
* to the agent process, not the prepareWorktree hook.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launchCommand.d.ts","sourceRoot":"","sources":["../../src/lib/launchCommand.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,GAAE,MAAwB,GAAG,MAAM,CAcvF;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,MAAwB,GAAG,MAAM,CAgB3E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,MAAM,CAMvF;AAsMD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA8B9D;AAED,QAAA,MAAM,wBAAwB,YAAI,oBAAoB,EAAE,qBAAqB,CAAU,CAAC;AAExF,KAAK,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC;AAEhF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAK1E;AAsBD,UAAU,sBAAsB;IAC9B,UAAU,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACnE;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACjD;;;OAGG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,sBAAsB,GAAG,MAAM,CAkC7E"}
|
|
1
|
+
{"version":3,"file":"launchCommand.d.ts","sourceRoot":"","sources":["../../src/lib/launchCommand.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,GAAE,MAAwB,GAAG,MAAM,CAcvF;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,MAAwB,GAAG,MAAM,CAgB3E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,MAAM,CAMvF;AAsMD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA8B9D;AAED,QAAA,MAAM,wBAAwB,YAAI,oBAAoB,EAAE,qBAAqB,CAAU,CAAC;AAExF,KAAK,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC;AAEhF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAK1E;AAsBD,MAAM,WAAW,yBAAyB;IACxC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,UAAU,sBAAsB;IAC9B,UAAU,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;;OAIG;IACH,MAAM,EAAE,WAAW,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACnE;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACjD;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAAC;IAClE;;;OAGG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,sBAAsB,GAAG,MAAM,CAkC7E"}
|
|
@@ -381,7 +381,12 @@ function buildUnwrappedHostLaunchCommand(arguments_) {
|
|
|
381
381
|
function buildSafehouseLaunchCommand(arguments_) {
|
|
382
382
|
const promptDir = path.dirname(arguments_.promptFile);
|
|
383
383
|
const safehouseCommandName = inferAgentCommandName(arguments_.definition.cmd);
|
|
384
|
-
const { agentCommand, prepareWorktreeCommand } = renderPrepareAndAgentCommand(arguments_);
|
|
384
|
+
const { agentCommand: rawAgentCommand, prepareWorktreeCommand } = renderPrepareAndAgentCommand(arguments_);
|
|
385
|
+
const { safehouseAgentIntegration } = arguments_;
|
|
386
|
+
const agentCommand = [
|
|
387
|
+
...(safehouseAgentIntegration?.commandPreludes ?? []),
|
|
388
|
+
rawAgentCommand,
|
|
389
|
+
].join("; ");
|
|
385
390
|
// Split --env-pass per wrap: the prepareWorktree wrap only needs build secrets (so
|
|
386
391
|
// `npm install` etc. can authenticate); the agent wrap only needs the
|
|
387
392
|
// user's preLaunchEnv (build secrets are `unset` on the host between the
|
|
@@ -392,14 +397,15 @@ function buildSafehouseLaunchCommand(arguments_) {
|
|
|
392
397
|
const agentEnvPassFlag = envPassFlag([
|
|
393
398
|
...(arguments_.definition.preLaunchEnv ?? []),
|
|
394
399
|
...workerEnvironmentNames(arguments_.workerEnvironment),
|
|
400
|
+
...(safehouseAgentIntegration?.envPass ?? []),
|
|
395
401
|
]);
|
|
396
402
|
// safehouse reads colon-separated paths from `--add-dirs`; both wraps get the
|
|
397
403
|
// same grant so the prepareWorktree hook and the agent can each reach git.
|
|
398
404
|
// Quote the whole value so shell-special chars survive; the trailing space
|
|
399
405
|
// separates it from the next argv token. See `resolveSafehouseAddDirs` for
|
|
400
406
|
// which paths these are and why.
|
|
401
|
-
const
|
|
402
|
-
const
|
|
407
|
+
const safehouseAddDirsFlag = safehousePathListFlag("--add-dirs", arguments_.safehouseAddDirs ?? []);
|
|
408
|
+
const safehouseAgentAddDirsReadOnlyFlag = safehousePathListFlag("--add-dirs-ro", safehouseAgentIntegration?.addDirsReadOnly ?? []);
|
|
403
409
|
const safehouseWrapper = safehouseClearanceWrapperCommand();
|
|
404
410
|
// Defensive shim+promptDir trap: by the time we arm it, `rm -rf <promptDir>`
|
|
405
411
|
// has already run (line below) so the promptDir wipe is a no-op on the happy
|
|
@@ -429,9 +435,12 @@ function buildSafehouseLaunchCommand(arguments_) {
|
|
|
429
435
|
// Running the real launch chain as `sh -c` would make it see `sh`, so use
|
|
430
436
|
// an agent-named symlink to /bin/sh. This preserves per-agent profile
|
|
431
437
|
// selection without enabling every agent profile.
|
|
432
|
-
`{ ${safehouseWrapper} ${safehouseAddDirsFlag}${agentEnvPassFlag}"$_safehouse_shim" -c ${shellSingleQuote(agentCommand)} sh "$_p"; _safehouse_status=$?; rm -rf "$_safehouse_shim_dir"; trap - EXIT; exit "$_safehouse_status"; }`);
|
|
438
|
+
`{ ${safehouseWrapper} ${safehouseAddDirsFlag}${safehouseAgentAddDirsReadOnlyFlag}${agentEnvPassFlag}"$_safehouse_shim" -c ${shellSingleQuote(agentCommand)} sh "$_p"; _safehouse_status=$?; rm -rf "$_safehouse_shim_dir"; trap - EXIT; exit "$_safehouse_status"; }`);
|
|
433
439
|
return lines.join(" && ");
|
|
434
440
|
}
|
|
441
|
+
function safehousePathListFlag(flagName, paths) {
|
|
442
|
+
return paths.length === 0 ? "" : `${flagName}=${shellSingleQuote(paths.join(":"))} `;
|
|
443
|
+
}
|
|
435
444
|
/**
|
|
436
445
|
* Benign baseline env the srt wraps run under (via `env -i`). This is an
|
|
437
446
|
* allowlist on purpose: srt's CLI spawns its child with the *inherited* host
|
|
@@ -10,8 +10,8 @@ There is a single path from board state to dispatch: `Source[] → Board → Dis
|
|
|
10
10
|
|
|
11
11
|
## Consequences
|
|
12
12
|
|
|
13
|
-
- The canonical seam is the `Issue` contract: a source emits `
|
|
13
|
+
- The canonical seam is the `Issue` contract: a source emits `agent` and `repository`, or the task is ignored (`isGroundcrewIssue` keys off exactly that). Consumers branch on the canonical `CanonicalStatus` enum, never on a source's native status names.
|
|
14
14
|
- **Linear-specific** concepts live in the adapter: `agent-*` label parsing, `agent-any` routing, sub-issue/parent detection, assigned-to-viewer + label selection policy.
|
|
15
|
-
- **Canonical** concepts stay in eligibility so every source benefits: blocker classification (sources populate `blockers[]`) and exhausted-
|
|
15
|
+
- **Canonical** concepts stay in eligibility so every source benefits: blocker classification (sources populate `blockers[]`) and exhausted-agent gating (sources pick an `agent`).
|
|
16
16
|
- This was a pure internal refactor with no user-visible change — Linear keeps working identically — so it carried no migration cost and landed before the breaking v5 cuts.
|
|
17
17
|
- Changing the Linear selection mechanism (assigned + labeled) is now an adapter-local change that does not touch the engine.
|
package/docs/commands.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
```bash
|
|
8
8
|
crew task list
|
|
9
9
|
crew task list --source todo --status todo --unblocked
|
|
10
|
-
crew task list --agent
|
|
10
|
+
crew task list --agent claude-fable --repo ClipboardHealth/api --json
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
`crew task get <task-id>` prints one normalized task. Canonical IDs such as `todo:GC-20260608-001` route directly to the named source. Natural IDs can be resolved with `--source <name>` or, when unique, by searching all configured sources. If more than one source matches, the command fails and asks for a canonical ID or `--source`.
|
|
@@ -23,7 +23,7 @@ crew task get todo:GC-20260608-001 --prompt
|
|
|
23
23
|
```bash
|
|
24
24
|
crew task create "Fix cancellation retry race" \
|
|
25
25
|
--source todo \
|
|
26
|
-
--agent
|
|
26
|
+
--agent claude-fable \
|
|
27
27
|
--repo ClipboardHealth/api \
|
|
28
28
|
--project marketplace \
|
|
29
29
|
--context backend \
|
|
@@ -35,7 +35,7 @@ Linear creation creates a Todo issue assigned to the current Linear API viewer,
|
|
|
35
35
|
```bash
|
|
36
36
|
crew task create "Fix cancellation retry race" \
|
|
37
37
|
--source linear \
|
|
38
|
-
--agent
|
|
38
|
+
--agent claude-fable \
|
|
39
39
|
--team ENG \
|
|
40
40
|
--repo ClipboardHealth/api \
|
|
41
41
|
--description "Investigate retry handling."
|
|
@@ -70,7 +70,7 @@ done and schedules the next `status:todo` recurrence itself.
|
|
|
70
70
|
```bash
|
|
71
71
|
crew task create "Run flaky triage sweep" \
|
|
72
72
|
--source todo \
|
|
73
|
-
--agent
|
|
73
|
+
--agent claude-fable \
|
|
74
74
|
--repo ClipboardHealth/groundcrew \
|
|
75
75
|
--id flaky-triage-1 \
|
|
76
76
|
--rec 2h \
|
package/docs/configuration.md
CHANGED
|
@@ -92,13 +92,40 @@ The "Loaded config from ..." line at startup tells you which config won.
|
|
|
92
92
|
|
|
93
93
|
## Agent Label Routing
|
|
94
94
|
|
|
95
|
-
- `agent-claude`, `agent-codex`, `agent-<name>` routes to that enabled
|
|
95
|
+
- `agent-claude`, `agent-codex`, `agent-<name>` routes to that enabled launch profile.
|
|
96
96
|
- `agent-any` routes to the agent with the most session headroom, after skipping agents over their session limit or weekly paced budget.
|
|
97
97
|
- Unknown `agent-<name>` falls back to `agents.default`.
|
|
98
98
|
- A built-in `agent-<name>` label whose agent is not enabled falls back to `agents.default` with a warning.
|
|
99
99
|
- No `agent-*` label is ignored by `crew run`. Dispatch on demand with `crew start <TASK>`, which falls back to `agents.default`.
|
|
100
100
|
- Todo tasks blocked by non-terminal blockers are skipped until their blockers reach a terminal status.
|
|
101
101
|
|
|
102
|
+
Agent names are launch profiles, not just vendor names. To choose a model per
|
|
103
|
+
task, define model-specific profiles and route tasks to them:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
export default {
|
|
107
|
+
agents: {
|
|
108
|
+
default: "claude-fable",
|
|
109
|
+
definitions: {
|
|
110
|
+
"claude-fable": {
|
|
111
|
+
cmd: "claude --model claude-fable-5 --permission-mode auto",
|
|
112
|
+
color: "#C15F3C",
|
|
113
|
+
usage: { codexbar: { provider: "claude" } },
|
|
114
|
+
},
|
|
115
|
+
"claude-opus": {
|
|
116
|
+
cmd: "claude --model claude-opus-4-8 --permission-mode auto",
|
|
117
|
+
color: "#8A4FFF",
|
|
118
|
+
usage: { codexbar: { provider: "claude" } },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use the same profile name in every source: Linear label `agent-claude-fable`,
|
|
126
|
+
todo.txt token `agent:claude-fable`, shell JSON `"agent": "claude-fable"`,
|
|
127
|
+
or `crew task create ... --agent claude-fable`.
|
|
128
|
+
|
|
102
129
|
Status classification uses Linear's default status names `In Progress` and `In Review` to disambiguate multiple `started` workflow states. Statuses that do not match those names fall back to Linear's workflow `state.type` (`unstarted`, `started`, `completed`, `canceled`, `duplicate`), so broad lifecycle classification still works without configuration. Parent issues with children are ignored; sub-issues are the work items.
|
|
103
130
|
|
|
104
131
|
If your Linear workflow uses different names, explicitly declare the built-in Linear source and override only the names you need:
|
|
@@ -167,9 +194,9 @@ export default {
|
|
|
167
194
|
|
|
168
195
|
Rules:
|
|
169
196
|
|
|
170
|
-
- `agents.definitions` is the enabled
|
|
197
|
+
- `agents.definitions` is the enabled launch profile set; `crew doctor` only probes listed profiles.
|
|
171
198
|
- Built-in entries can be `{}` or partial overrides such as `{ cmd: "..." }`.
|
|
172
|
-
- Custom
|
|
199
|
+
- Custom launch profile names must provide `cmd` and `color`.
|
|
173
200
|
- `agents.default` must point at an enabled agent.
|
|
174
201
|
- Legacy agent entries like `codex: { disabled: true }` are rejected with migration guidance; remove unwanted entries instead.
|
|
175
202
|
|
|
@@ -244,9 +271,9 @@ and hook contract.
|
|
|
244
271
|
| `orchestrator.pollIntervalMilliseconds` | `120_000` | Poll interval in `--watch` mode. |
|
|
245
272
|
| `orchestrator.sessionLimitPercentage` | `85` | Number in `(0, 100]`. An agent whose codexbar session window exceeds this percentage is skipped that tick. Agents are also skipped when codexbar reports weekly usage over the current weekly paced budget. |
|
|
246
273
|
| `agents.default` | `"claude"` | Tiebreak for `agent-any` resolution and fallback for explicit but unknown `agent-*` labels. Also used by `crew start <TASK>` for unlabeled tasks. `crew run` ignores unlabeled tasks and does not apply this default. Must exist in `agents.definitions`. If you enable only `codex`, set `default: "codex"`. |
|
|
247
|
-
| `agents.definitions` | **required** | Enabled
|
|
248
|
-
| `agents.definitions.<name>.cmd` | preset for built-ins | Shell command launched for the agent. Required for custom
|
|
249
|
-
| `agents.definitions.<name>.color` | preset for built-ins | Color for the workspace status pill (cmux only; tmux and zellij silently drop it). Required for custom
|
|
274
|
+
| `agents.definitions` | **required** | Enabled launch profile set. Built-in keys (`claude`, `codex`) can use `{}` to opt into the shipped preset. Custom profile names must provide `cmd` and `color`; use custom profiles such as `claude-fable` and `claude-opus` to select model-specific commands per task. |
|
|
275
|
+
| `agents.definitions.<name>.cmd` | preset for built-ins | Shell command launched for the agent. Required for custom profiles. Runs in the worktree through the resolved `local.runner`. `{{worktree}}` is replaced before launch; `{{sandbox}}` expands to the sbx sandbox name under the sdx runner and an empty string otherwise. |
|
|
276
|
+
| `agents.definitions.<name>.color` | preset for built-ins | Color for the workspace status pill (cmux only; tmux and zellij silently drop it). Required for custom profiles. |
|
|
250
277
|
| `agents.definitions.<name>.usage` | preset for built-ins | If set, codexbar usage is fetched for this agent and gated by `sessionLimitPercentage` plus the weekly paced budget when codexbar exposes a weekly window. When `usage.codexbar.source` is omitted, groundcrew uses `oauth` for Codex/Claude on macOS, `auto` for other macOS providers, and `cli` elsewhere. Set to `{ disabled: true }` to disable usage gating while keeping the agent enabled. |
|
|
251
278
|
| `agents.definitions.<name>.sandbox` | optional | Docker Sandboxes binding for the agent. Required at launch when `local.runner` resolves to `sdx`. Field: `agent` (required sbx agent name). Groundcrew assumes the `groundcrew-<agent>` sandbox already exists. |
|
|
252
279
|
| `agents.definitions.<name>.preLaunch` | optional | Host-only shell snippet run before the agent exec and outside Safehouse/sdx. Exports survive into the launch shell; under the default `safehouse` runner they are only forwarded to the agent when listed via `preLaunchEnv` or when `cmd` includes its own `safehouse --env-pass=NAMES`. `{{worktree}}` is substituted. A non-zero exit aborts launch. Not supported when `local.runner` resolves to `sdx` in v1. |
|
package/docs/task-sources.md
CHANGED
|
@@ -53,7 +53,7 @@ state is expected or explicitly allowed.
|
|
|
53
53
|
"description": "Task body",
|
|
54
54
|
"status": "todo",
|
|
55
55
|
"repository": "your-org/your-repo",
|
|
56
|
-
"
|
|
56
|
+
"agent": "claude-fable",
|
|
57
57
|
"assignee": "Alice",
|
|
58
58
|
"updatedAt": "2026-05-22T15:00:00Z",
|
|
59
59
|
"blockers": [{ "id": "JIRA-122", "title": "Schema migration", "status": "done" }],
|
|
@@ -63,7 +63,7 @@ state is expected or explicitly allowed.
|
|
|
63
63
|
]
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
Allowed `status` values are `todo`, `in-progress`, `in-review`, `done`, and `other`.
|
|
66
|
+
Allowed `status` values are `todo`, `in-progress`, `in-review`, `done`, and `other`. Omit `repository` or `agent` when a task should not be groundcrew-eligible. `hasMoreBlockers` is optional and defaults to `false`; `sourceRef` is opaque data that groundcrew passes back to your writeback command.
|
|
67
67
|
|
|
68
68
|
## Todo.txt
|
|
69
69
|
|
|
@@ -89,7 +89,7 @@ Creating a todo task appends a line with `status:todo` as the final meaningful t
|
|
|
89
89
|
```bash
|
|
90
90
|
crew task create "Fix cancellation retry race" \
|
|
91
91
|
--source todo \
|
|
92
|
-
--agent
|
|
92
|
+
--agent claude-fable \
|
|
93
93
|
--repo ClipboardHealth/api \
|
|
94
94
|
--project marketplace \
|
|
95
95
|
--context backend \
|
|
@@ -97,7 +97,7 @@ crew task create "Fix cancellation retry race" \
|
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
```txt
|
|
100
|
-
Fix cancellation retry race +marketplace @backend id:GC-20260608-001 repo:ClipboardHealth/api agent:
|
|
100
|
+
Fix cancellation retry race +marketplace @backend id:GC-20260608-001 repo:ClipboardHealth/api agent:claude-fable status:todo
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
For hand-written todo lines, a non-empty title is enough prompt text when `.tasks/<id>.md` is absent. Omit `agent:` to default to `agent:any`:
|
|
@@ -126,7 +126,7 @@ export default {
|
|
|
126
126
|
```bash
|
|
127
127
|
crew task create "Fix cancellation retry race" \
|
|
128
128
|
--source linear \
|
|
129
|
-
--agent
|
|
129
|
+
--agent claude-fable \
|
|
130
130
|
--repo ClipboardHealth/api \
|
|
131
131
|
--description "Investigate retry handling."
|
|
132
132
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/groundcrew",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.36.1",
|
|
4
4
|
"description": "Linear-driven orchestrator that launches AI coding agents in git worktrees, with workspace lifecycle and usage tracking.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@anthropic-ai/sandbox-runtime": "0.0.52",
|
|
72
|
-
"@clipboard-health/clearance": "1.2
|
|
72
|
+
"@clipboard-health/clearance": "1.3.2",
|
|
73
73
|
"@linear/sdk": "86.0.0",
|
|
74
74
|
"cosmiconfig": "9.0.1",
|
|
75
75
|
"tslib": "2.8.1",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"cspell": "10.0.1",
|
|
88
88
|
"dependency-cruiser": "17.4.3",
|
|
89
89
|
"husky": "9.1.7",
|
|
90
|
-
"jscpd": "
|
|
90
|
+
"jscpd": "5.0.5",
|
|
91
91
|
"knip": "6.15.0",
|
|
92
92
|
"lint-staged": "17.0.7",
|
|
93
93
|
"markdownlint-cli2": "0.22.1",
|