agenthub-multiagent-mcp 1.32.0 → 1.33.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.
@@ -0,0 +1,128 @@
1
+ /**
2
+ * add-ai-agent-employees §1 — the employee layer for the dispatcher.
3
+ *
4
+ * An "employee" is an agent bound to a versioned Charter and a seniority tier
5
+ * (server-side, Phase 0). The dispatcher (daemon) loads this context once at
6
+ * startup and, for every work trigger, builds a charter-grounded SHIFT PROMPT:
7
+ * the worker session perceives → plans → acts → reports, with tier-appropriate
8
+ * supervision rules embedded.
9
+ *
10
+ * Enforcement layering (be honest about which layer does what):
11
+ * - capability invokes: HARD-gated server-side by the Phase-0 policy
12
+ * chokepoint (gate → plan-review 202; deny → 403) regardless of anything
13
+ * the worker session does locally.
14
+ * - git-level irreversible actions (merge, push to main): enforced by repo
15
+ * branch protection + the shift prompt's standing rules; probationary/
16
+ * junior workers must submit_plan and wait for approval.
17
+ */
18
+ /**
19
+ * fetchEmployee loads the employee + charter for an agent. Returns null when
20
+ * the agent is not an employee (404), the feature is off (503), or the server
21
+ * is unreachable — the daemon then behaves exactly as it does today.
22
+ */
23
+ export async function fetchEmployee(apiUrl, apiKey, agentId) {
24
+ try {
25
+ const resp = await fetch(`${apiUrl}/api/employees/${encodeURIComponent(agentId)}`, { headers: { "X-API-Key": apiKey } });
26
+ if (!resp.ok)
27
+ return null; // 404 not_employee | 503 employees_disabled
28
+ const data = (await resp.json());
29
+ if (!data.employee || !data.charter || data.employee.status !== "active") {
30
+ return null;
31
+ }
32
+ return {
33
+ agentId,
34
+ tier: data.employee.tier ?? "probationary",
35
+ status: data.employee.status,
36
+ model: data.employee.model ?? "",
37
+ charter: data.charter,
38
+ };
39
+ }
40
+ catch {
41
+ return null; // network failure → plain-daemon behaviour, never crash startup
42
+ }
43
+ }
44
+ /** Tiers whose irreversible actions always require an approved plan-review. */
45
+ const SUPERVISED_TIERS = new Set(["probationary", "junior"]);
46
+ /**
47
+ * buildShiftPrompt renders the charter-grounded worker prompt for one trigger.
48
+ * Structure: identity+charter → standing rules (tier-dependent) → the trigger
49
+ * → the shift loop contract (perceive/plan/act/report).
50
+ */
51
+ export function buildShiftPrompt(ctx, trigger) {
52
+ const c = ctx.charter;
53
+ const supervised = SUPERVISED_TIERS.has(ctx.tier);
54
+ const charterBlock = [
55
+ `You are "${ctx.agentId}", an AI employee on AgentHub.`,
56
+ `Role: ${c.role_name} (charter v${c.version}, tier: ${ctx.tier})`,
57
+ c.mission ? `Mission: ${c.mission}` : "",
58
+ c.responsibilities ? `Responsibilities: ${c.responsibilities}` : "",
59
+ c.scope ? `Scope of authority: ${c.scope}` : "",
60
+ c.success_metrics ? `Success metrics: ${c.success_metrics}` : "",
61
+ ].filter(Boolean).join("\n");
62
+ const rules = [
63
+ "STANDING RULES (non-negotiable):",
64
+ "- Work ONLY within your charter's scope. If a step falls outside it, stop and escalate via send_message to your owner instead of improvising.",
65
+ "- All code work happens on a feature branch. NEVER merge, never push to main/master.",
66
+ supervised
67
+ ? "- Your tier is supervised: before ANY irreversible action (opening a PR counts as the end of your shift; merging, deploying, sending outbound, or spending are FORBIDDEN), call submit_plan describing the action and wait for approval via check_review_status. If denied, stop and report."
68
+ : "- Gate high-risk irreversible actions through submit_plan; low-risk actions within your charter may proceed.",
69
+ "- If a capability invoke returns 202 pending_review, that is the policy gate: poll check_review_status; re-invoke only after approval. A 403 policy_denied is final — escalate, do not retry.",
70
+ ].join("\n");
71
+ const triggerBlock = trigger.kind === "task"
72
+ ? [
73
+ "TRIGGER — assigned task:",
74
+ `Task ID: ${trigger.taskId ?? ""}`,
75
+ `Task: ${trigger.task ?? ""}`,
76
+ `Assigned by: ${trigger.assignedBy ?? ""}`,
77
+ `Priority: ${trigger.priority ?? "normal"}`,
78
+ ].join("\n")
79
+ : [
80
+ "TRIGGER — message:",
81
+ `From: ${trigger.fromAgent ?? ""}`,
82
+ `Subject: ${trigger.subject ?? ""}`,
83
+ `Body:\n${trigger.body ?? ""}`,
84
+ trigger.messageId ? `Reply with the reply tool to message_id="${trigger.messageId}".` : "",
85
+ ].filter(Boolean).join("\n");
86
+ const loop = [
87
+ "SHIFT LOOP:",
88
+ "1. PERCEIVE — check_inbox (unread_only=true); if this is a task, accept_task with the task id; read any context the task references.",
89
+ "2. PLAN — outline the steps; for supervised tiers submit_plan before irreversible steps.",
90
+ "3. ACT — do the work. For tasks: report_progress at meaningful milestones (25/50/75).",
91
+ "4. REPORT — when done (or blocked): agent_complete_task (or agent_report_blocked with the blocker), then close the shift with session_close_report summarising what shipped and what's next.",
92
+ ].join("\n");
93
+ return [charterBlock, rules, triggerBlock, loop].join("\n\n");
94
+ }
95
+ /**
96
+ * Engineering IC charter template — the P1 first hire. Used as the default by
97
+ * employee_hire when role_name is "Engineering IC" and no guardrails given.
98
+ */
99
+ export const CHARTER_TEMPLATES = {
100
+ "Platform Ops": {
101
+ role_name: "Platform Ops",
102
+ mission: "Monitor platform health, post digests and alerts, keep agents unblocked.",
103
+ responsibilities: "Watch deploys/CI/stalls; triage incidents; escalate real risk; run periodic reviews of reports.",
104
+ scope: "Read/alert autonomously; deployment-class actions gate.",
105
+ success_metrics: "Stall detection latency; escalation accuracy; rollback rate.",
106
+ guardrails: { allowed_capabilities: ["*"], break_glass: ["prod_deploy", "deploy"] },
107
+ },
108
+ Coordinator: {
109
+ role_name: "Coordinator",
110
+ mission: "Synthesize status, route work between agents, keep the org brain current.",
111
+ responsibilities: "Standup synthesis; task routing; brain hygiene; onboarding context for new agents.",
112
+ scope: "Read everything; outbound communication gates.",
113
+ success_metrics: "Routing accuracy; escalation accuracy; brain freshness.",
114
+ guardrails: { allowed_capabilities: ["*"], irreversible: ["send_email", "broadcast"], break_glass: ["prod_deploy", "deploy"] },
115
+ },
116
+ };
117
+ export const ENG_IC_CHARTER = {
118
+ role_name: "Engineering IC",
119
+ mission: "Pick up assigned tickets, implement them end-to-end on feature branches with tests, open PRs, and respond to review feedback.",
120
+ responsibilities: "Claim assigned tasks; implement with TDD; keep commits small; open a PR per task; report progress and close each shift with a session report.",
121
+ scope: "Code changes on feature branches in the bound project's repositories. No merges, no deploys, no outbound communication beyond AgentHub messages.",
122
+ success_metrics: "Task completion rate; review approval ratio; rollback rate; escalation accuracy.",
123
+ guardrails: {
124
+ allowed_capabilities: ["*"],
125
+ break_glass: ["prod_deploy", "deploy"],
126
+ },
127
+ };
128
+ //# sourceMappingURL=employee.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"employee.js","sourceRoot":"","sources":["../src/employee.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=employee.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"employee.test.d.ts","sourceRoot":"","sources":["../src/employee.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { fetchEmployee, buildShiftPrompt, ENG_IC_CHARTER, } from "./employee.js";
3
+ // add-ai-agent-employees §1 — the employee layer must (a) never break the
4
+ // plain daemon when the agent isn't an employee / the feature is off, and
5
+ // (b) render shift prompts that carry the charter + tier supervision rules.
6
+ function ctx(tier) {
7
+ return {
8
+ agentId: "eng-ic-1",
9
+ tier,
10
+ status: "active",
11
+ charter: {
12
+ id: "ch-1",
13
+ role_name: "Engineering IC",
14
+ version: 2,
15
+ mission: "Ship tickets end-to-end.",
16
+ scope: "Feature branches only.",
17
+ guardrails: { allowed_capabilities: ["*"] },
18
+ },
19
+ };
20
+ }
21
+ describe("fetchEmployee", () => {
22
+ let fetchMock;
23
+ beforeEach(() => {
24
+ fetchMock = vi.fn();
25
+ vi.stubGlobal("fetch", fetchMock);
26
+ });
27
+ afterEach(() => vi.unstubAllGlobals());
28
+ it("returns context for an active employee (incl. model pin)", async () => {
29
+ fetchMock.mockResolvedValue(new Response(JSON.stringify({
30
+ employee: { tier: "junior", status: "active", model: "claude-haiku-4-5" },
31
+ charter: { id: "c1", role_name: "Engineering IC", version: 1, guardrails: {} },
32
+ }), { status: 200 }));
33
+ const got = await fetchEmployee("https://hub.test", "key", "eng-ic-1");
34
+ expect(got?.tier).toBe("junior");
35
+ expect(got?.model).toBe("claude-haiku-4-5");
36
+ expect(got?.charter.role_name).toBe("Engineering IC");
37
+ // Auth header present
38
+ const [url, init] = fetchMock.mock.calls[0];
39
+ expect(String(url)).toContain("/api/employees/eng-ic-1");
40
+ expect(init.headers).toMatchObject({ "X-API-Key": "key" });
41
+ });
42
+ it.each([404, 503])("returns null on HTTP %d (non-employee / feature off)", async (status) => {
43
+ fetchMock.mockResolvedValue(new Response("{}", { status }));
44
+ expect(await fetchEmployee("https://hub.test", "key", "a")).toBeNull();
45
+ });
46
+ it("returns null for a suspended employee", async () => {
47
+ fetchMock.mockResolvedValue(new Response(JSON.stringify({
48
+ employee: { tier: "junior", status: "suspended" },
49
+ charter: { id: "c1", role_name: "R", version: 1, guardrails: {} },
50
+ }), { status: 200 }));
51
+ expect(await fetchEmployee("https://hub.test", "key", "a")).toBeNull();
52
+ });
53
+ it("returns null on network failure (daemon must not crash)", async () => {
54
+ fetchMock.mockRejectedValue(new Error("ECONNREFUSED"));
55
+ expect(await fetchEmployee("https://hub.test", "key", "a")).toBeNull();
56
+ });
57
+ });
58
+ describe("buildShiftPrompt", () => {
59
+ it("embeds charter identity, role, version, and tier", () => {
60
+ const p = buildShiftPrompt(ctx("probationary"), { kind: "task", taskId: "t1", task: "Fix bug" });
61
+ expect(p).toContain('You are "eng-ic-1"');
62
+ expect(p).toContain("Engineering IC (charter v2, tier: probationary)");
63
+ expect(p).toContain("Mission: Ship tickets end-to-end.");
64
+ expect(p).toContain("Scope of authority: Feature branches only.");
65
+ });
66
+ it("supervised tiers must submit_plan before irreversible actions", () => {
67
+ for (const tier of ["probationary", "junior"]) {
68
+ const p = buildShiftPrompt(ctx(tier), { kind: "task", taskId: "t1", task: "X" });
69
+ expect(p).toContain("Your tier is supervised");
70
+ expect(p).toContain("submit_plan");
71
+ expect(p).toContain("check_review_status");
72
+ }
73
+ });
74
+ it("senior/lead get the lighter gate rule, not the supervised one", () => {
75
+ for (const tier of ["senior", "lead"]) {
76
+ const p = buildShiftPrompt(ctx(tier), { kind: "task", taskId: "t1", task: "X" });
77
+ expect(p).not.toContain("Your tier is supervised");
78
+ expect(p).toContain("Gate high-risk irreversible actions");
79
+ }
80
+ });
81
+ it("never allows merging or pushing to main at any tier", () => {
82
+ for (const tier of ["probationary", "junior", "senior", "lead"]) {
83
+ const p = buildShiftPrompt(ctx(tier), { kind: "task", taskId: "t1", task: "X" });
84
+ expect(p).toContain("NEVER merge, never push to main/master");
85
+ }
86
+ });
87
+ it("task triggers carry id/title/assigner; the loop closes with a session report", () => {
88
+ const p = buildShiftPrompt(ctx("junior"), {
89
+ kind: "task", taskId: "t42", task: "Add endpoint", assignedBy: "sumit", priority: "high",
90
+ });
91
+ expect(p).toContain("Task ID: t42");
92
+ expect(p).toContain("Add endpoint");
93
+ expect(p).toContain("Assigned by: sumit");
94
+ expect(p).toContain("session_close_report");
95
+ expect(p).toContain("report_progress");
96
+ });
97
+ it("message triggers include reply instructions with the message id", () => {
98
+ const p = buildShiftPrompt(ctx("junior"), {
99
+ kind: "message", messageId: "m7", fromAgent: "ops", subject: "S", body: "B",
100
+ });
101
+ expect(p).toContain('message_id="m7"');
102
+ expect(p).toContain("From: ops");
103
+ });
104
+ it("explains the 202 pending_review policy-gate protocol", () => {
105
+ const p = buildShiftPrompt(ctx("junior"), { kind: "task", taskId: "t1", task: "X" });
106
+ expect(p).toContain("202 pending_review");
107
+ expect(p).toContain("403 policy_denied");
108
+ });
109
+ });
110
+ describe("ENG_IC_CHARTER template", () => {
111
+ it("declares deploys as break-glass and feature-branch-only scope", () => {
112
+ expect(ENG_IC_CHARTER.guardrails.break_glass).toContain("prod_deploy");
113
+ expect(ENG_IC_CHARTER.scope).toContain("feature branches");
114
+ });
115
+ });
116
+ //# sourceMappingURL=employee.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"employee.test.js","sourceRoot":"","sources":["../src/employee.test.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,42 @@
1
- #!/bin/bash
2
- # Wrapper script for daemon to invoke claude -p with prompt from file
3
- # Usage: run-claude.sh <prompt-file> <mcp-config-file> <max-turns>
4
-
5
- PROMPT_FILE="$1"
6
- MCP_CONFIG="$2"
7
- MAX_TURNS="${3:-1}"
8
-
9
- if [ ! -f "$PROMPT_FILE" ]; then
10
- echo "Error: prompt file not found: $PROMPT_FILE" >&2
11
- exit 1
12
- fi
13
-
14
- PROMPT="$(cat "$PROMPT_FILE")"
15
-
16
- claude -p "$PROMPT" \
17
- --dangerously-skip-permissions \
18
- --max-turns "$MAX_TURNS" \
19
- --output-format text \
20
- --mcp-config "$MCP_CONFIG" \
21
- --strict-mcp-config
1
+ #!/bin/bash
2
+ # Wrapper script for daemon/worker to invoke claude -p with prompt from file
3
+ # Usage: run-claude.sh <prompt-file> <mcp-config-file> <max-turns> [settings-file] [channels]
4
+
5
+ PROMPT_FILE="$1"
6
+ MCP_CONFIG="$2"
7
+ MAX_TURNS="${3:-3}"
8
+ SETTINGS_FILE="$4"
9
+ CHANNELS="$5"
10
+ MODEL="$6"
11
+
12
+ if [ ! -f "$PROMPT_FILE" ]; then
13
+ echo "Error: prompt file not found: $PROMPT_FILE" >&2
14
+ exit 1
15
+ fi
16
+
17
+ PROMPT="$(cat "$PROMPT_FILE")"
18
+
19
+ # Build optional flags
20
+ EXTRA_FLAGS=""
21
+ if [ -n "$SETTINGS_FILE" ] && [ -f "$SETTINGS_FILE" ]; then
22
+ EXTRA_FLAGS="$EXTRA_FLAGS --settings $SETTINGS_FILE"
23
+ fi
24
+ if [ -n "$CHANNELS" ]; then
25
+ EXTRA_FLAGS="$EXTRA_FLAGS --dangerously-load-development-channels $CHANNELS"
26
+ fi
27
+ if [ -n "$MODEL" ]; then
28
+ EXTRA_FLAGS="$EXTRA_FLAGS --model $MODEL"
29
+ fi
30
+
31
+ # Run claude, filter out "Reached max turns" error from stdout
32
+ OUTPUT=$(claude -p "$PROMPT" \
33
+ --dangerously-skip-permissions \
34
+ --max-turns "$MAX_TURNS" \
35
+ --output-format text \
36
+ --mcp-config "$MCP_CONFIG" \
37
+ $EXTRA_FLAGS 2>/dev/null)
38
+
39
+ # Strip "Error: Reached max turns" line if present
40
+ echo "$OUTPUT" | grep -v "^Error: Reached max turns"
41
+
42
+ exit 0
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAqD,MAAM,cAAc,CAAC;AACrG,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AA6B/D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,MAAM,WAAW,CAAC;CACnC;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAwJD,wBAAgB,aAAa,IAAI,IAAI,EAAE,CA8xEtC;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,OAAO,CAAC,CAkqElB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAqD,MAAM,cAAc,CAAC;AACrG,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AA8B/D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,MAAM,WAAW,CAAC;CACnC;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAwJD,wBAAgB,aAAa,IAAI,IAAI,EAAE,CAs0EtC;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,OAAO,CAAC,CAitElB"}
@@ -9,6 +9,7 @@ import { getBrain } from "../brain/backend.js";
9
9
  import open from "open";
10
10
  import { registerOpenSpecVizTools, handleOpenSpecVizToolCall } from "./openspec-viz/index.js";
11
11
  import { getServerTime, useTimeInjection } from "../lib/server-time.js";
12
+ import { ENG_IC_CHARTER } from "../employee.js";
12
13
  /**
13
14
  * Background sync: pushes local context to server after every save.
14
15
  * Non-blocking — logs errors but never throws.
@@ -1178,6 +1179,42 @@ export function registerTools() {
1178
1179
  required: ["task_id", "progress"],
1179
1180
  },
1180
1181
  },
1182
+ // AI employees (add-ai-agent-employees §1)
1183
+ {
1184
+ name: "employee_hire",
1185
+ description: "Hire an agent as an AI employee: creates a versioned Charter (role, mission, guardrails) and binds the agent at tier probationary. role_name 'Engineering IC' with no guardrails uses the built-in Eng-IC template. Requires AGENTHUB_EMPLOYEES_ENABLED on the server.",
1186
+ inputSchema: {
1187
+ type: "object",
1188
+ properties: {
1189
+ agent_id: { type: "string", description: "Agent to hire" },
1190
+ role_name: { type: "string", description: "Role title, e.g. 'Engineering IC'" },
1191
+ mission: { type: "string", description: "One-paragraph mission" },
1192
+ responsibilities: { type: "string", description: "What the role does day-to-day" },
1193
+ scope: { type: "string", description: "Scope of authority" },
1194
+ success_metrics: { type: "string", description: "How performance is judged" },
1195
+ guardrails: {
1196
+ type: "object",
1197
+ description: "Policy guardrails: {allowed_capabilities:[...]/['*'], irreversible:[], low_risk:[], break_glass:[]}",
1198
+ },
1199
+ tier: {
1200
+ type: "string",
1201
+ description: "Starting tier (default probationary)",
1202
+ enum: ["probationary", "junior", "senior", "lead"],
1203
+ },
1204
+ },
1205
+ required: ["agent_id", "role_name"],
1206
+ },
1207
+ },
1208
+ {
1209
+ name: "employee_get",
1210
+ description: "Get an agent's employee record + charter (role, tier, guardrails). 404 when the agent is not an employee; 503 when employees are disabled.",
1211
+ inputSchema: {
1212
+ type: "object",
1213
+ properties: {
1214
+ agent_id: { type: "string", description: "Agent to look up (defaults to self)" },
1215
+ },
1216
+ },
1217
+ },
1181
1218
  // Ticket creation tools
1182
1219
  {
1183
1220
  name: "create_epic",
@@ -3303,6 +3340,53 @@ export async function handleToolCall(name, args, client, context) {
3303
3340
  ],
3304
3341
  };
3305
3342
  }
3343
+ // AI employees (add-ai-agent-employees §1)
3344
+ case "employee_hire": {
3345
+ if (!agentId)
3346
+ throw new Error("Not registered. Call agent_register first.");
3347
+ const roleName = args.role_name;
3348
+ let req = {
3349
+ agent_id: args.agent_id,
3350
+ role_name: roleName,
3351
+ mission: args.mission,
3352
+ responsibilities: args.responsibilities,
3353
+ scope: args.scope,
3354
+ success_metrics: args.success_metrics,
3355
+ guardrails: args.guardrails,
3356
+ tier: args.tier,
3357
+ };
3358
+ // No guardrails for the canonical first hire → built-in Eng-IC template.
3359
+ if (!args.guardrails && roleName === ENG_IC_CHARTER.role_name) {
3360
+ req = {
3361
+ ...req,
3362
+ mission: req.mission ?? ENG_IC_CHARTER.mission,
3363
+ responsibilities: req.responsibilities ?? ENG_IC_CHARTER.responsibilities,
3364
+ scope: req.scope ?? ENG_IC_CHARTER.scope,
3365
+ success_metrics: req.success_metrics ?? ENG_IC_CHARTER.success_metrics,
3366
+ guardrails: ENG_IC_CHARTER.guardrails,
3367
+ };
3368
+ }
3369
+ const result = await client.hireEmployee(req);
3370
+ return {
3371
+ content: [
3372
+ {
3373
+ type: "text",
3374
+ text: `Hired ${req.agent_id} as "${roleName}":\n${JSON.stringify(result, null, 2)}`,
3375
+ },
3376
+ ],
3377
+ };
3378
+ }
3379
+ case "employee_get": {
3380
+ const target = args.agent_id || agentId;
3381
+ if (!target)
3382
+ throw new Error("Not registered. Call agent_register first.");
3383
+ const result = await client.getEmployee(target);
3384
+ return {
3385
+ content: [
3386
+ { type: "text", text: JSON.stringify(result, null, 2) },
3387
+ ],
3388
+ };
3389
+ }
3306
3390
  // Ticket creation tools
3307
3391
  case "create_epic": {
3308
3392
  if (!agentId)