@openparachute/agent 0.2.2 → 0.2.3-rc.2

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.
@@ -52,7 +52,7 @@
52
52
  "module": "vault",
53
53
  "event": "note.created",
54
54
  "filter": {
55
- "tags": ["#agent/message/inbound"],
55
+ "tags": ["agent/message/inbound"],
56
56
  "has_metadata": ["channel"],
57
57
  "missing_metadata": ["channel_inbound_rendered_at"]
58
58
  }
@@ -85,7 +85,7 @@
85
85
  "module": "vault",
86
86
  "event": "note.created",
87
87
  "filter": {
88
- "tags": ["#agent/definition"]
88
+ "tags": ["agent/definition"]
89
89
  }
90
90
  },
91
91
  "sink": {
@@ -110,7 +110,7 @@
110
110
  "module": "vault",
111
111
  "event": "note.updated",
112
112
  "filter": {
113
- "tags": ["#agent/definition"]
113
+ "tags": ["agent/definition"]
114
114
  }
115
115
  },
116
116
  "sink": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openparachute/agent",
3
- "version": "0.2.2",
3
+ "version": "0.2.3-rc.2",
4
4
  "description": "Vault-native agents for Claude Code — a #agent/definition note + an inbound message becomes a sandboxed claude turn; the reply is written back as a note. Messaging gateway on :1941.",
5
5
  "license": "AGPL-3.0",
6
6
  "type": "module",
@@ -375,8 +375,8 @@ describe("DefVaultClient", () => {
375
375
  const client = new DefVaultClient(binding);
376
376
  const notes = await client.listDefNotes();
377
377
  expect(urls).toHaveLength(1);
378
- // `#agent/definition` → `%23agent%2Fdefinition` (both `#` and `/` encoded).
379
- expect(urls[0]).toContain("tag=%23agent%2Fdefinition");
378
+ // `agent/definition` → `agent%2Fdefinition` (the `/` percent-encoded).
379
+ expect(urls[0]).toContain("tag=agent%2Fdefinition");
380
380
  expect(urls[0]).toContain("include_content=true");
381
381
  expect(auth).toBe("Bearer write-token");
382
382
  expect(notes.map((n) => n.id)).toEqual(["Agents/uni-dev", "Agents/researcher"]);
@@ -444,7 +444,7 @@ describe("DefVaultClient", () => {
444
444
  expect(created.id).toBe("Agents/newbot");
445
445
  expect(captured!.method).toBe("POST");
446
446
  expect(captured!.url).toContain("/vault/default/api/notes");
447
- expect(captured!.body.tags).toEqual(["#agent/definition"]);
447
+ expect(captured!.body.tags).toEqual(["agent/definition"]);
448
448
  expect(captured!.body.content).toBe("P");
449
449
  expect((captured!.body.metadata as Record<string, string>).name).toBe("newbot");
450
450
  expect(captured!.body.path).toBe("Agents/newbot");
@@ -538,7 +538,7 @@ function vaultFetch(opts: {
538
538
  opts.patches?.push({ id, status: meta.status, pending: meta.pending });
539
539
  return new Response(null, { status: 200 });
540
540
  }
541
- if (u.includes("/api/notes?") && u.includes("tag=%23agent%2Fdefinition")) {
541
+ if (u.includes("/api/notes?") && u.includes("tag=agent%2Fdefinition")) {
542
542
  return new Response(JSON.stringify(opts.defs ?? []), {
543
543
  status: 200,
544
544
  headers: { "content-type": "application/json" },
@@ -678,7 +678,7 @@ describe("AgentDefRegistry — lifecycle", () => {
678
678
  const u = String(url);
679
679
  const method = init?.method ?? "GET";
680
680
  if (method === "PATCH") return new Response(null, { status: 200 });
681
- if (u.includes("/api/notes?") && u.includes("tag=%23agent%2Fdefinition")) {
681
+ if (u.includes("/api/notes?") && u.includes("tag=agent%2Fdefinition")) {
682
682
  return new Response(JSON.stringify(present), { status: 200, headers: { "content-type": "application/json" } });
683
683
  }
684
684
  return new Response("[]", { status: 200 });
@@ -714,7 +714,7 @@ describe("AgentDefRegistry — lifecycle", () => {
714
714
  const u = String(url);
715
715
  const method = init?.method ?? "GET";
716
716
  if (method === "PATCH") return new Response(null, { status: 200 });
717
- if (u.includes("/api/notes?") && u.includes("tag=%23agent%2Fdefinition")) {
717
+ if (u.includes("/api/notes?") && u.includes("tag=agent%2Fdefinition")) {
718
718
  return new Response(JSON.stringify(current), { status: 200, headers: { "content-type": "application/json" } });
719
719
  }
720
720
  return new Response("[]", { status: 200 });
@@ -752,7 +752,7 @@ describe("AgentDefRegistry — lifecycle", () => {
752
752
  const fetchFn = (async (url: string | URL | Request) => {
753
753
  const u = String(url);
754
754
  if (u.includes("/vault/default/")) return new Response("boom", { status: 500 });
755
- if (u.includes("/vault/research/") && u.includes("tag=%23agent%2Fdefinition")) {
755
+ if (u.includes("/vault/research/") && u.includes("tag=agent%2Fdefinition")) {
756
756
  return new Response(JSON.stringify([{ id: "r1", content: "role", metadata: { name: "r" } }]), {
757
757
  status: 200,
758
758
  });
@@ -1217,7 +1217,7 @@ describe("AgentDefRegistry — grant-GC reconcile (#96)", () => {
1217
1217
  );
1218
1218
  }
1219
1219
  }
1220
- if (u.includes("/api/notes?") && u.includes("tag=%23agent%2Fdefinition")) {
1220
+ if (u.includes("/api/notes?") && u.includes("tag=agent%2Fdefinition")) {
1221
1221
  return new Response(JSON.stringify(present), { status: 200, headers: { "content-type": "application/json" } });
1222
1222
  }
1223
1223
  return new Response("[]", { status: 200 });
@@ -1309,7 +1309,7 @@ describe("AgentDefRegistry — grant-GC reconcile (#96)", () => {
1309
1309
  reconciled.push({ agent: body.agent, liveConnections: body.liveConnections });
1310
1310
  return new Response(JSON.stringify({ pruned: 0 }), { status: 200 });
1311
1311
  }
1312
- if (u.includes("/api/notes?") && u.includes("tag=%23agent%2Fdefinition")) {
1312
+ if (u.includes("/api/notes?") && u.includes("tag=agent%2Fdefinition")) {
1313
1313
  return new Response(JSON.stringify(present), { status: 200, headers: { "content-type": "application/json" } });
1314
1314
  }
1315
1315
  return new Response("[]", { status: 200 });
@@ -1339,7 +1339,7 @@ describe("AgentDefRegistry — grant-GC reconcile (#96)", () => {
1339
1339
  reconciled.push({ agent: body.agent, liveConnections: body.liveConnections });
1340
1340
  return new Response(JSON.stringify({ pruned: 0 }), { status: 200 });
1341
1341
  }
1342
- if (u.includes("/api/notes?") && u.includes("tag=%23agent%2Fdefinition")) {
1342
+ if (u.includes("/api/notes?") && u.includes("tag=agent%2Fdefinition")) {
1343
1343
  if (listShouldFail) return new Response("boom", { status: 500 });
1344
1344
  return new Response(JSON.stringify(present), { status: 200, headers: { "content-type": "application/json" } });
1345
1345
  }
@@ -1408,7 +1408,7 @@ function vaultFetchWithDelete(opts: {
1408
1408
  return new Response(status >= 400 ? "delete failed" : null, { status });
1409
1409
  }
1410
1410
  if (method === "PATCH") return new Response(null, { status: 200 });
1411
- if (u.includes("/api/notes?") && u.includes("tag=%23agent%2Fdefinition")) {
1411
+ if (u.includes("/api/notes?") && u.includes("tag=agent%2Fdefinition")) {
1412
1412
  return new Response(JSON.stringify(opts.defs), {
1413
1413
  status: 200,
1414
1414
  headers: { "content-type": "application/json" },
@@ -77,9 +77,9 @@ describe("buildSpecFromBody", () => {
77
77
  const spec = buildSpecFromBody({
78
78
  name: "a",
79
79
  channels: ["c"],
80
- vault: { name: "default", access: "write", tags: ["#agent/message"] },
80
+ vault: { name: "default", access: "write", tags: ["agent/message"] },
81
81
  });
82
- expect(spec.vault).toEqual({ name: "default", access: "write", tags: ["#agent/message"] });
82
+ expect(spec.vault).toEqual({ name: "default", access: "write", tags: ["agent/message"] });
83
83
  });
84
84
 
85
85
  test("rejects a bad filesystem / network value", () => {
@@ -210,7 +210,7 @@ function specWithVault(name = "eng"): AgentSpec {
210
210
  return {
211
211
  name,
212
212
  channels: [name],
213
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
213
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
214
214
  };
215
215
  }
216
216
 
@@ -222,7 +222,7 @@ function specWithSystemPrompt(
222
222
  return {
223
223
  name,
224
224
  channels: [name],
225
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
225
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
226
226
  systemPrompt: prompt,
227
227
  ...(mode ? { systemPromptMode: mode } : {}),
228
228
  };
@@ -234,7 +234,7 @@ function specMultiThreaded(name = "eng"): AgentSpec {
234
234
  name,
235
235
  channels: [name],
236
236
  mode: "multi-threaded",
237
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
237
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
238
238
  };
239
239
  }
240
240
 
@@ -735,7 +735,7 @@ function specWithWorkspace(workspace: string, name = "eng"): AgentSpec {
735
735
  return {
736
736
  name,
737
737
  channels: [name],
738
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
738
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
739
739
  workspace,
740
740
  };
741
741
  }
@@ -773,7 +773,7 @@ describe("ProgrammaticBackend.deliver — workspace seam: cwd = workspace, secre
773
773
  const spec: AgentSpec = {
774
774
  name: "eng",
775
775
  channels: ["eng"],
776
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
776
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
777
777
  workspace: workspaceDir,
778
778
  systemPrompt: "Work in the repo.",
779
779
  };
@@ -309,7 +309,7 @@ describe("GET /api/agent-defs", () => {
309
309
  fake.seed({
310
310
  id: "Agents/uni-dev",
311
311
  content: "a".repeat(500), // long prompt → preview truncates to 200.
312
- tags: ["#agent/definition"],
312
+ tags: ["agent/definition"],
313
313
  metadata: { name: "uni-dev", backend: "attached", mode: "multi-threaded" },
314
314
  });
315
315
  const { reg } = registryWithFakeVault({ fake });
@@ -351,7 +351,7 @@ describe("GET /api/agent-defs/:noteId (full def)", () => {
351
351
  fake.seed({
352
352
  id: "Agents/uni-dev",
353
353
  content: "F".repeat(500), // long body → list preview truncates; full returns all.
354
- tags: ["#agent/definition"],
354
+ tags: ["agent/definition"],
355
355
  metadata: { name: "uni-dev", backend: "attached", mode: "multi-threaded", wants: "vault:research:read" },
356
356
  });
357
357
  const { reg } = registryWithFakeVault({ fake });
@@ -459,7 +459,7 @@ describe("POST /api/agent-defs", () => {
459
459
  // The note was written to the fake vault, tagged the def tag, body = prompt.
460
460
  const written = [...fake.notes.values()].find((n) => n.metadata.name === "newbot");
461
461
  expect(written).toBeDefined();
462
- expect(written!.tags).toContain("#agent/definition");
462
+ expect(written!.tags).toContain("agent/definition");
463
463
  expect(written!.content).toBe("You are newbot.");
464
464
  expect(written!.metadata.backend).toBe("programmatic");
465
465
  // It instantiated LIVE (the per-note reload ran ensureChannel + register) — not
@@ -555,7 +555,7 @@ describe("POST /api/agent-defs", () => {
555
555
  fake.seed({
556
556
  id: "Agents/uni-dev",
557
557
  content: "p",
558
- tags: ["#agent/definition"],
558
+ tags: ["agent/definition"],
559
559
  metadata: { name: "uni-dev", backend: "programmatic" },
560
560
  });
561
561
  const { reg } = registryWithFakeVault({ fake });
@@ -586,7 +586,7 @@ describe("PATCH /api/agent-defs/:noteId", () => {
586
586
  fake.seed({
587
587
  id: "Agents/uni-dev",
588
588
  content: "old prompt",
589
- tags: ["#agent/definition"],
589
+ tags: ["agent/definition"],
590
590
  metadata: { name: "uni-dev", backend: "programmatic" },
591
591
  });
592
592
  const { reg, calls } = registryWithFakeVault({ fake });
@@ -657,7 +657,7 @@ describe("DELETE /api/agent-defs/:noteId", () => {
657
657
  fake.seed({
658
658
  id: "Agents/uni-dev",
659
659
  content: "p",
660
- tags: ["#agent/definition"],
660
+ tags: ["agent/definition"],
661
661
  metadata: { name: "uni-dev", backend: "programmatic" },
662
662
  });
663
663
  const { reg, calls } = registryWithFakeVault({ fake });
@@ -226,7 +226,7 @@ describe("GET /api/agents/<name>/env — composes all three sources + precedence
226
226
  fake.seed({
227
227
  id: "Agents/uni-dev",
228
228
  content: "You are uni-dev.",
229
- tags: ["#agent/definition"],
229
+ tags: ["agent/definition"],
230
230
  metadata: { name: "uni-dev", backend: "programmatic", mode: "single-threaded", wants: "env:github" },
231
231
  });
232
232
  const grants = grantsClientWith({ github: githubGrantStatus });
@@ -308,7 +308,7 @@ describe("GET /api/agents/<name>/env — resilient when grants/hub unreachable",
308
308
  fake.seed({
309
309
  id: "Agents/uni-dev",
310
310
  content: "You are uni-dev.",
311
- tags: ["#agent/definition"],
311
+ tags: ["agent/definition"],
312
312
  metadata: { name: "uni-dev", backend: "programmatic", mode: "single-threaded", wants: "env:github" },
313
313
  });
314
314
  // A grants client whose hub fetch always throws — registerGrant fails at instantiate,
@@ -130,7 +130,7 @@ function inboundBody(noteId: string, channel = "eng") {
130
130
  id: noteId,
131
131
  path: `channel/${channel}/${noteId}`,
132
132
  content: "wake up session",
133
- tags: ["#agent/message", "#agent/message/inbound"],
133
+ tags: ["agent/message", "agent/message/inbound"],
134
134
  metadata: { channel, direction: "inbound", sender: "aaron" },
135
135
  },
136
136
  });
@@ -596,7 +596,7 @@ describe("C — AGENT_VAULT_TRIGGER_TEMPLATE exposed via /.parachute/config", ()
596
596
  // re-registration updates the existing trigger in place. The TAG is
597
597
  // #agent/message and the webhook is on the /agent mount.
598
598
  expect(body.triggerTemplate.name).toBe("channel_inbound_<channel>");
599
- expect(body.triggerTemplate.when.tags).toEqual(["#agent/message/inbound"]);
599
+ expect(body.triggerTemplate.when.tags).toEqual(["agent/message/inbound"]);
600
600
  // CONTRACT: the predicate keys on the `agent` routing key (was `channel`).
601
601
  expect(body.triggerTemplate.when.has_metadata).toEqual(["agent"]);
602
602
  // The rendered-at marker NAME is unchanged (cosmetic/internal).
@@ -194,7 +194,7 @@ describe("POST /api/jobs — create + validation", () => {
194
194
  expect(body.job.noteId).toBe("Channels/eng/jobs/x"); // vault note id for addressing
195
195
  const post = calls.find((c) => c.url.endsWith("/api/notes") && c.init.method === "POST")!;
196
196
  const sent = JSON.parse(String(post.init.body));
197
- expect(sent.tags).toEqual(["#agent/job"]);
197
+ expect(sent.tags).toEqual(["agent/job"]);
198
198
  expect(sent.content).toBe("do it"); // trimmed
199
199
  expect(sent.metadata.enabled).toBe("true");
200
200
  expect(sent.metadata.jobId).toBe("x");
@@ -224,7 +224,7 @@ describe("POST /api/jobs/:id/run — fire now", () => {
224
224
  // The injected note is INBOUND with the #agent/message tags.
225
225
  const inject = calls.find((c) => c.url.endsWith("/api/notes") && c.init.method === "POST")!;
226
226
  const sent = JSON.parse(String(inject.init.body));
227
- expect(sent.tags).toEqual(["#agent/message", "#agent/message/inbound"]);
227
+ expect(sent.tags).toEqual(["agent/message", "agent/message/inbound"]);
228
228
  expect(sent.metadata.sender).toBe("runner:Channels/eng/jobs/x");
229
229
  } finally { srv.stop(true); }
230
230
  });
@@ -413,7 +413,7 @@ describe("Vault inbound webhook — POST /api/vault/inbound", () => {
413
413
  function body(
414
414
  noteId: string,
415
415
  extraMeta: Record<string, unknown> = {},
416
- tags: string[] = ["#agent/message", "#agent/message/inbound"],
416
+ tags: string[] = ["agent/message", "agent/message/inbound"],
417
417
  ) {
418
418
  return JSON.stringify({
419
419
  trigger: "channel-inbound",
@@ -546,7 +546,7 @@ describe("Vault inbound webhook — POST /api/vault/inbound", () => {
546
546
  note: {
547
547
  id: "agent-only-1",
548
548
  content: "wake up via agent key",
549
- tags: ["#agent/message", "#agent/message/inbound"],
549
+ tags: ["agent/message", "agent/message/inbound"],
550
550
  // NO `channel` field — the routing key is carried ONLY under the new `agent` alias.
551
551
  metadata: { agent: "eng", direction: "inbound", sender: "aaron" },
552
552
  },
@@ -571,7 +571,7 @@ describe("Vault inbound webhook — POST /api/vault/inbound", () => {
571
571
  note: {
572
572
  id: "channel-only-1",
573
573
  content: "wake up via legacy channel key",
574
- tags: ["#agent/message", "#agent/message/inbound"],
574
+ tags: ["agent/message", "agent/message/inbound"],
575
575
  // ONLY the legacy `channel` field — a pre-expand writer; must still route.
576
576
  metadata: { channel: "eng", direction: "inbound", sender: "aaron" },
577
577
  },
@@ -618,13 +618,13 @@ describe("Vault inbound webhook — POST /api/vault/inbound", () => {
618
618
  }
619
619
  });
620
620
 
621
- test("#agent/message/outbound-tagged note is ack'd 200 but NOT emitted (belt-and-suspenders)", async () => {
621
+ test("agent/message/outbound-tagged note is ack'd 200 but NOT emitted (belt-and-suspenders)", async () => {
622
622
  const { srv, base, emitted } = buildVaultServer();
623
623
  try {
624
624
  const res = await fetch(`${base}/api/vault/inbound?secret=${SECRET}`, {
625
625
  method: "POST",
626
626
  headers: { "content-type": "application/json" },
627
- body: body("ob-1", { direction: "outbound" }, ["#agent/message", "#agent/message/outbound"]),
627
+ body: body("ob-1", { direction: "outbound" }, ["agent/message", "agent/message/outbound"]),
628
628
  });
629
629
  expect(res.status).toBe(200);
630
630
  expect(emitted).toHaveLength(0);
package/src/jobs.test.ts CHANGED
@@ -126,7 +126,7 @@ describe("VaultJobStore — vault-native CRUD", () => {
126
126
  const jobs = await store.listAll();
127
127
  // Only ONE vault transport in the map → queried exactly once (telegram is skipped).
128
128
  expect(urls.filter((u) => u.includes("/api/notes")).length).toBe(1);
129
- expect(urls[0]).toContain("tag=%23agent%2Fjob");
129
+ expect(urls[0]).toContain("tag=agent%2Fjob");
130
130
  expect(jobs).toHaveLength(2);
131
131
  expect(jobs[0]).toMatchObject({
132
132
  id: "note-1",
@@ -190,7 +190,7 @@ describe("VaultJobStore — vault-native CRUD", () => {
190
190
  expect(saved.noteId).toBe("Channels/uni-dev/jobs/morning");
191
191
  expect(calls).toHaveLength(1);
192
192
  const body = JSON.parse(String(calls[0]!.init.body));
193
- expect(body.tags).toEqual(["#agent/job"]);
193
+ expect(body.tags).toEqual(["agent/job"]);
194
194
  expect(body.path).toBe("Channels/uni-dev/jobs/morning");
195
195
  expect(body.metadata.jobId).toBe("morning"); // slug persisted for stable display
196
196
  expect(body.content).toBe("Run the morning weave");
@@ -68,12 +68,12 @@ describe("mintScopedToken — happy path", () => {
68
68
  {
69
69
  scope: "vault:default:read",
70
70
  audience: "vault.default",
71
- permissions: { scoped_tags: ["#agent/message"] },
71
+ permissions: { scoped_tags: ["agent/message"] },
72
72
  },
73
73
  depsWith(hub.fetchFn),
74
74
  );
75
75
  expect(hub.calls[0]!.body.audience).toBe("vault.default");
76
- expect(hub.calls[0]!.body.permissions).toEqual({ scoped_tags: ["#agent/message"] });
76
+ expect(hub.calls[0]!.body.permissions).toEqual({ scoped_tags: ["agent/message"] });
77
77
  });
78
78
  });
79
79
 
@@ -74,7 +74,7 @@ describe("module.json — modular-UI declaration", () => {
74
74
  expect(tmpl?.requestedBy).toBe("agent");
75
75
  expect(tmpl?.source?.module).toBe("vault");
76
76
  expect(tmpl?.source?.event).toBe("note.created");
77
- expect(tmpl?.source?.filter?.tags).toContain("#agent/message/inbound");
77
+ expect(tmpl?.source?.filter?.tags).toContain("agent/message/inbound");
78
78
  expect(tmpl?.sink?.module).toBe("agent");
79
79
  expect(tmpl?.sink?.action).toBe("message.deliver");
80
80
  // It's PARAMETERIZED — the operator picks the vault + names the channel.
@@ -128,7 +128,7 @@ describe("module.json — modular-UI declaration", () => {
128
128
  expect(tmpl?.requestedBy).toBe("agent");
129
129
  expect(tmpl?.source?.module).toBe("vault");
130
130
  // Filters on the def tag — and ONLY that tag (no inbound-message keys).
131
- expect(tmpl?.source?.filter?.tags).toEqual(["#agent/definition"]);
131
+ expect(tmpl?.source?.filter?.tags).toEqual(["agent/definition"]);
132
132
  expect(tmpl?.sink?.module).toBe("agent");
133
133
  expect(tmpl?.sink?.action).toBe("definition.reload");
134
134
  // Parameterized: the operator picks which def-vault. No channel param
@@ -264,7 +264,7 @@ describe("inbound for a programmatic channel → deliver → outbound note", ()
264
264
  note: {
265
265
  id: noteId,
266
266
  content,
267
- tags: ["#agent/message", "#agent/message/inbound"],
267
+ tags: ["agent/message", "agent/message/inbound"],
268
268
  metadata: { channel, direction: "inbound", sender: "aaron", ts: "2026-06-16T00:00:01Z" },
269
269
  },
270
270
  }),
@@ -356,7 +356,7 @@ describe("inbound for an EXPECTED-but-not-yet-registered channel → queued pend
356
356
  note: {
357
357
  id: noteId,
358
358
  content,
359
- tags: ["#agent/message", "#agent/message/inbound"],
359
+ tags: ["agent/message", "agent/message/inbound"],
360
360
  metadata: { channel, direction: "inbound", sender: "aaron", ts: "2026-06-16T00:00:01Z" },
361
361
  },
362
362
  }),
@@ -16,7 +16,7 @@ describe("parseArgs — name + channels + vault + egress + mounts → the right
16
16
  "--channel",
17
17
  "ops:read",
18
18
  "--vault",
19
- "default:read:#agent/message,#decision",
19
+ "default:read:agent/message,#decision",
20
20
  "--egress",
21
21
  "registry.npmjs.org,github.com",
22
22
  "--mount",
@@ -38,7 +38,7 @@ describe("parseArgs — name + channels + vault + egress + mounts → the right
38
38
  expect(spec!.vault).toEqual({
39
39
  name: "default",
40
40
  access: "read",
41
- tags: ["#agent/message", "#decision"],
41
+ tags: ["agent/message", "#decision"],
42
42
  });
43
43
 
44
44
  // Egress: additive host list, comma-split.
@@ -448,7 +448,7 @@ describe("spawnAgent — full wiring with stubs (no real token)", () => {
448
448
  const spec: AgentSpec = {
449
449
  name: "aaron-dev",
450
450
  channels: ["aaron-dev"],
451
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
451
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
452
452
  network: "restricted", // exercise the egress floor; scoped reads are the default (step 6)
453
453
  };
454
454
  const res = await spawnAgent(spec, baseDeps({ tmux, sandboxEngine: engine }));
@@ -570,13 +570,13 @@ describe("spawnAgent — full wiring with stubs (no real token)", () => {
570
570
  const spec: AgentSpec = {
571
571
  name: "weaver",
572
572
  channels: ["c"],
573
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
573
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
574
574
  };
575
575
  await spawnAgent(spec, baseDeps({ fetchFn }));
576
576
  const vaultCall = calls.find((c) => String(c.scope).startsWith("vault:"));
577
577
  expect(vaultCall).toBeDefined();
578
578
  expect(vaultCall!.scope).toBe("vault:default:read");
579
- expect(vaultCall!.permissions).toEqual({ scoped_tags: ["#agent/message"] });
579
+ expect(vaultCall!.permissions).toEqual({ scoped_tags: ["agent/message"] });
580
580
  });
581
581
 
582
582
  test("idempotent: an already-running session is a no-op", async () => {
@@ -674,7 +674,7 @@ describe("spawnAgent — full wiring with stubs (no real token)", () => {
674
674
  const spec: AgentSpec = {
675
675
  name: "weaver",
676
676
  channels: [{ name: "weave", access: "read" }],
677
- vault: { name: "default", access: "read", tags: ["#agent/message"] },
677
+ vault: { name: "default", access: "read", tags: ["agent/message"] },
678
678
  network: "restricted",
679
679
  egress: ["registry.npmjs.org"],
680
680
  };