feat: multi-work is able to delegate to root
CI / verify (pull_request) Successful in 9s

This commit is contained in:
2026-09-18 20:13:54 +02:00
parent 8b6836f5a4
commit 52e98c9d78
9 changed files with 376 additions and 88 deletions
+87 -51
View File
@@ -9,16 +9,24 @@ import { randomUUID } from "node:crypto";
import { Herdr, rootSchema } from "./herdr.js";
import { multiWorkGuide } from "./routing.js";
export const bindingSchema = z.object({
owner: z.string(),
child: z.string(),
projectID: z.string(),
root: rootSchema,
directory: z.string(),
workspaceID: z.string(),
branch: z.string(),
ready: z.boolean(),
});
export const bindingSchema = z
.object({
owner: z.string(),
child: z.string(),
projectID: z.string(),
root: rootSchema,
directory: z.string(),
workspaceID: z.string(),
branch: z.string(),
ready: z.boolean(),
})
.refine(
(binding) =>
binding.directory === binding.root.directory
? binding.workspaceID === binding.root.workspaceID && binding.branch === "root"
: binding.workspaceID !== binding.root.workspaceID,
{ message: "Invalid multi-work placement metadata" },
);
export const bindingKey = (id: string) => `multi-work:${id}`;
const inputSchema = z
.object({
@@ -98,7 +106,7 @@ export const installMultiWork = (
agent.name = Agent.Name.make("multi-work");
agent.mode = "primary";
agent.description =
"Coordinate independent tasks in Herdr worktrees; retrieve local facts with fast-lo.";
"Coordinate independent tasks locally or in Herdr worktrees; retrieve local facts with fast-lo.";
agent.system = multiWorkGuide;
agent.permissions = [
...coordinate.permissions.filter((rule) => rule.action !== "subagent"),
@@ -137,14 +145,14 @@ export const installMultiWork = (
child.projectID !== binding.projectID ||
child.location.directory !== binding.directory
)
throw new Error("Coordinate child does not match its ready worktree binding");
throw new Error("Coordinate child does not match its ready multi-work binding");
const parent = yield* context.session.get({ sessionID: child.parentID });
if (
parent.agent !== "multi-work" ||
parent.projectID !== binding.projectID ||
parent.location.directory !== binding.root.directory
)
throw new Error("Worktree owner changed agent or location");
throw new Error("Binding owner changed agent or location");
return binding;
});
@@ -184,7 +192,7 @@ export const installMultiWork = (
agent: { type: "string", enum: ["fast-lo", "coordinate"] },
};
tool.description =
"Delegate to fast-lo locally, or coordinate in a new Herdr worktree using worktree: {base, branch?, label?}. Prefer descriptive human-readable branch and label values, for example {base:'main',branch:'fix/login-timeout',label:'Fix login timeout'}. Continue an owned coordinate child with sessionID and no worktree argument; naming fields are create-only. Native background and results apply.";
"Delegate to fast-lo for retrieval, or coordinate in this root checkout by omitting worktree. To isolate new coordinate work, use worktree: {base, branch?, label?}. Continue an owned coordinate child with sessionID and no worktree argument. Native background and results apply.";
}
}).pipe(Effect.orDie),
);
@@ -208,9 +216,7 @@ export const installMultiWork = (
throw new Error("A bound coordinate child cannot be repurposed");
if (call.agent !== "multi-work") {
if (input.worktree || input.agent === "coordinate")
throw new Error(
"Only multi-work may initialize coordinate worktrees",
);
throw new Error("Only multi-work may delegate to coordinate");
return yield* native.execute(input, call);
}
const parent = yield* context.session.get({ sessionID: call.sessionID });
@@ -240,29 +246,9 @@ export const installMultiWork = (
}
if (input.agent !== "coordinate")
throw new Error("multi-work delegates only to fast-lo or coordinate");
if (
input.sessionID
? input.worktree !== undefined
: input.worktree === undefined
)
if (input.sessionID && input.worktree !== undefined)
throw new Error(
"New coordinate work requires worktree: {base}; resumes require only sessionID",
);
const { data: agent } = yield* context.agent.get({
agentID: call.agent,
location: { directory: parent.location.directory },
});
const permission = [
...agent.permissions,
...(parent.permissions ?? []),
].findLast(
(rule) =>
matches("herdr_worktree", rule.action) &&
matches(root.directory, rule.resource),
)?.effect;
if (permission !== "allow")
throw new Error(
`herdr_worktree requires explicit allow; custom approval is unavailable (${permission ?? "ask"})`,
"Coordinate resumes require only sessionID; worktree is create-only",
);
const lock = input.sessionID ?? `${call.sessionID}:${call.id}`;
if (busy.has(lock)) throw new Error("This delegation is already active");
@@ -274,17 +260,48 @@ export const installMultiWork = (
if (input.sessionID) {
const binding = yield* validate(Session.ID.make(input.sessionID));
if (binding.owner !== call.sessionID)
throw new Error("Cannot resume another parent's worktree");
yield* Effect.tryPromise((signal) =>
herdr.verify(
binding.directory,
binding.workspaceID,
binding.root,
binding.branch,
signal,
),
);
throw new Error("Cannot resume another parent's binding");
placement = binding;
}
if (
input.worktree ||
(placement && placement.directory !== placement.root.directory)
) {
const { data: agent } = yield* context.agent.get({
agentID: call.agent,
location: { directory: parent.location.directory },
});
const permission = [
...agent.permissions,
...(parent.permissions ?? []),
].findLast(
(rule) =>
matches("herdr_worktree", rule.action) &&
matches(root.directory, rule.resource),
)?.effect;
if (permission !== "allow")
throw new Error(
`herdr_worktree requires explicit allow; custom approval is unavailable (${permission ?? "ask"})`,
);
}
if (placement) {
const binding = placement;
if (
root.directory !== binding.root.directory ||
root.workspaceID !== binding.root.workspaceID ||
root.repo !== binding.root.repo
)
throw new Error("Bound Herdr root is no longer available");
if (binding.directory !== binding.root.directory)
yield* Effect.tryPromise((signal) =>
herdr.verify(
binding.directory,
binding.workspaceID,
binding.root,
binding.branch,
signal,
),
);
initialized = true;
}
const { worktree, ...args } = input;
@@ -310,8 +327,6 @@ export const installMultiWork = (
);
childLock = id;
busy.add(id);
if (!worktree)
throw new Error("Missing worktree initialization");
const sessionID = Session.ID.make(id);
const child = yield* context.session.get({ sessionID });
if (
@@ -323,6 +338,27 @@ export const installMultiWork = (
throw new Error(
"Native executor returned an unexpected child",
);
if (!worktree) {
const binding = {
owner: call.sessionID,
child: id,
projectID: parent.projectID,
root,
directory: root.directory,
workspaceID: root.workspaceID,
branch: "root",
ready: true,
};
yield* context.storage.set(callKey, {
child: id,
branch: binding.branch,
root,
});
yield* context.storage.set(bindingKey(id), binding);
placement = binding;
initialized = true;
return;
}
const branch =
worktree.branch ?? `multi-work/${randomUUID()}`;
yield* context.storage.set(callKey, {