patchcord 0.6.33 → 0.6.35
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/.claude-plugin/plugin.json +1 -1
- package/bin/patchcord.mjs +186 -40
- package/package.json +1 -1
- package/scripts/subscribe.mjs +12 -1
- package/skills/inbox/SKILL.md +8 -0
package/bin/patchcord.mjs
CHANGED
|
@@ -222,14 +222,29 @@ team (run from the project root):
|
|
|
222
222
|
patchcord team status reconcile folder ↔ identity ↔ tmux ↔ token
|
|
223
223
|
patchcord team launch launch each worker in mux
|
|
224
224
|
|
|
225
|
-
projects (cloud-only —
|
|
226
|
-
|
|
227
|
-
|
|
225
|
+
projects (cloud-only — groups your own namespaces into one initiative.
|
|
226
|
+
NOT just a label: the LEADS of Teams in one project can message each other
|
|
227
|
+
with no handshake. Any NON-lead still needs an approved link, below.):
|
|
228
|
+
patchcord project list projects + their Teams
|
|
229
|
+
patchcord project create <name> explicit; nothing else creates one
|
|
230
|
+
patchcord project rename <project-id> <new-name> label only; reach unchanged
|
|
231
|
+
patchcord project rm <project-id> Teams survive, un-grouped
|
|
232
|
+
patchcord namespace set-project <ns> <project> assign (project must exist)
|
|
233
|
+
patchcord namespace set-project <ns> <project> --create create it, then assign
|
|
234
|
+
patchcord namespace set-project <ns> un-group it
|
|
235
|
+
patchcord provision ... --project <name> [--create-project]
|
|
236
|
+
patchcord orchestrator ... --project <name> [--create-project]
|
|
237
|
+
|
|
238
|
+
A namespace in NO project has no cross-team peers at all — that is the
|
|
239
|
+
default and it is deliberate. Assignment never invents a project: an
|
|
240
|
+
unknown name is an error, because silently creating one on a typo made
|
|
241
|
+
mistyped projects invisible and unmanageable.
|
|
228
242
|
|
|
229
243
|
cross-namespace links (cloud-only, no CLI — agent-to-agent via MCP:
|
|
230
244
|
request_namespace_link(ns, agent) / respond_namespace_link(ns, agent, approve)
|
|
231
|
-
/ list_my_namespace_links. Any agent, no lead role —
|
|
232
|
-
named agent, never the whole namespace
|
|
245
|
+
/ list_my_namespace_links. Any agent, no lead role — each link is to ONE
|
|
246
|
+
named agent, never the whole namespace. This is the ONLY way to reach a
|
|
247
|
+
non-lead in another namespace, project or no project.)
|
|
233
248
|
|
|
234
249
|
schedules:
|
|
235
250
|
patchcord schedule create <name> --namespace <ns> --to <agent> --content "..."
|
|
@@ -1169,7 +1184,7 @@ if (cmd === "subscribe") {
|
|
|
1169
1184
|
// account token (user-level, tied to NO agent) lives at ~/.patchcord/auth.json
|
|
1170
1185
|
// (legacy: main.json / master.json) or $PATCHCORD_TOKEN (legacy: *_MAIN/MASTER).
|
|
1171
1186
|
// `patchcord login` authenticates; everything else logs in on demand.
|
|
1172
|
-
if (cmd === "login" || cmd === "orchestrator" || cmd === "teamlead" || cmd === "provision" || cmd === "pull" || cmd === "team" || cmd === "schedule" || cmd === "namespace") {
|
|
1187
|
+
if (cmd === "login" || cmd === "orchestrator" || cmd === "teamlead" || cmd === "provision" || cmd === "pull" || cmd === "team" || cmd === "schedule" || cmd === "namespace" || cmd === "project" || cmd === "projects") {
|
|
1173
1188
|
const M = { cyan: "\x1b[36m", green: "\x1b[32m", dim: "\x1b[2m", rst: "\x1b[0m" };
|
|
1174
1189
|
const AUTH_CONFIG = join(HOME, ".patchcord", "auth.json");
|
|
1175
1190
|
const LEGACY_CONFIGS = [join(HOME, ".patchcord", "main.json"), join(HOME, ".patchcord", "master.json")];
|
|
@@ -1195,6 +1210,42 @@ if (cmd === "login" || cmd === "orchestrator" || cmd === "teamlead" || cmd === "
|
|
|
1195
1210
|
const forgetAuth = () => {
|
|
1196
1211
|
for (const p of [AUTH_CONFIG, ...LEGACY_CONFIGS]) { try { unlinkSync(p); } catch {} }
|
|
1197
1212
|
};
|
|
1213
|
+
// Assign a namespace to a project, shared by `provision --project` and
|
|
1214
|
+
// `orchestrator --project`.
|
|
1215
|
+
//
|
|
1216
|
+
// Assignment RESOLVES an existing project and NEVER creates one. The server
|
|
1217
|
+
// used to create a project for any name it did not recognise, so a typo
|
|
1218
|
+
// silently produced a new, invisible project — the defect that got an earlier
|
|
1219
|
+
// version of this feature abandoned. `--create-project` makes creation an
|
|
1220
|
+
// explicit act rather than a side effect of misspelling.
|
|
1221
|
+
//
|
|
1222
|
+
// warnOnly: a failure here must not fail the whole command. The agent
|
|
1223
|
+
// identity is already provisioned and the credential is already on disk;
|
|
1224
|
+
// exiting non-zero would make a working identity look like a failed one.
|
|
1225
|
+
const assignProject = async (ns, project, { warnOnly = false, label = "done" } = {}) => {
|
|
1226
|
+
if (process.argv.includes("--create-project")) {
|
|
1227
|
+
const { status: cStatus, json: cJson } = await accountCall("POST", "/api/projects", { name: project });
|
|
1228
|
+
if (cStatus === "201") console.log(` ${M.dim}created project "${project}"${M.rst}`);
|
|
1229
|
+
else if (cStatus !== "409") {
|
|
1230
|
+
console.error(` ${M.dim}warning: could not create project "${project}" (HTTP ${cStatus}): ${cJson?.error || ""}${M.rst}`);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
const { status, json } = await accountCall("POST", "/api/namespace/set-project", { namespace_id: ns, project });
|
|
1234
|
+
if (status === "200") {
|
|
1235
|
+
console.log(` ${M.dim}namespace ${ns} assigned to project "${project}" — its lead can now reach other leads in that project${M.rst}`);
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
if (status === "404") {
|
|
1239
|
+
console.error(` ${M.dim}warning: ${label}, but there is no project named "${project}".${M.rst}`);
|
|
1240
|
+
console.error(` ${M.dim} create it: patchcord project create ${project}${M.rst}`);
|
|
1241
|
+
console.error(` ${M.dim} or re-run with --create-project${M.rst}`);
|
|
1242
|
+
} else {
|
|
1243
|
+
const retry = json?.retryable ? " (transient — retry shortly, your login is fine)" : "";
|
|
1244
|
+
console.error(` ${M.dim}warning: ${label}, but --project failed (HTTP ${status}): ${json?.error || ""}${retry}${M.rst}`);
|
|
1245
|
+
}
|
|
1246
|
+
if (!warnOnly) process.exit(1);
|
|
1247
|
+
return false;
|
|
1248
|
+
};
|
|
1198
1249
|
const flagVal = (name, def = "") => {
|
|
1199
1250
|
const eq = process.argv.find((a) => a.startsWith(`--${name}=`));
|
|
1200
1251
|
if (eq) return eq.split("=").slice(1).join("=");
|
|
@@ -1504,45 +1555,144 @@ if (cmd === "login" || cmd === "orchestrator" || cmd === "teamlead" || cmd === "
|
|
|
1504
1555
|
writeFileSync(tj, JSON.stringify(man, null, 2) + "\n");
|
|
1505
1556
|
}
|
|
1506
1557
|
} catch {}
|
|
1507
|
-
// --project assigns this namespace to a project
|
|
1508
|
-
//
|
|
1509
|
-
//
|
|
1510
|
-
//
|
|
1511
|
-
//
|
|
1512
|
-
//
|
|
1558
|
+
// --project assigns this namespace to a project: a grouping entity above
|
|
1559
|
+
// the namespace. It DOES affect cross-namespace messaging — Teams in one
|
|
1560
|
+
// project get a standing LEAD-TO-LEAD channel with no handshake. Reaching a
|
|
1561
|
+
// NON-lead elsewhere still needs an approved namespace_links pair.
|
|
1562
|
+
//
|
|
1563
|
+
// Separate call: provisioning creates the agent identity, project assignment
|
|
1564
|
+
// groups the NAMESPACE — safe to retry independently. Assignment RESOLVES an
|
|
1565
|
+
// existing project and never creates one, so an unknown name is a 404, not a
|
|
1566
|
+
// new project; pass --create-project to create it first, deliberately.
|
|
1513
1567
|
if (project) {
|
|
1514
|
-
|
|
1515
|
-
if (pStatus !== "200") {
|
|
1516
|
-
console.error(` ${M.dim}warning: provisioned OK, but --project failed (HTTP ${pStatus}): ${pJson?.error || ""}${M.rst}`);
|
|
1517
|
-
} else {
|
|
1518
|
-
console.log(` ${M.dim}namespace ${ns} assigned to project "${project}"${M.rst}`);
|
|
1519
|
-
}
|
|
1568
|
+
await assignProject(ns, project, { warnOnly: true, label: "provisioned OK" });
|
|
1520
1569
|
}
|
|
1521
1570
|
console.log(`✓ provisioned ${M.green}${ns}:${arg}${M.rst} [${tool}${role ? "/" + role : ""}${lead ? "/lead" : ""}] → ${dir}`);
|
|
1522
1571
|
process.exit(0);
|
|
1523
1572
|
}
|
|
1524
1573
|
|
|
1525
1574
|
if (cmd === "namespace") {
|
|
1526
|
-
// Cloud-only: group namespaces into a
|
|
1527
|
-
//
|
|
1528
|
-
//
|
|
1529
|
-
//
|
|
1530
|
-
//
|
|
1575
|
+
// Cloud-only: group namespaces into a PROJECT — a grouping entity above the
|
|
1576
|
+
// namespace. It is NOT merely a label: Teams in one project get a standing
|
|
1577
|
+
// LEAD-TO-LEAD message channel with no per-pair handshake. Reaching any
|
|
1578
|
+
// NON-lead in another namespace still requires an approved namespace_links
|
|
1579
|
+
// pair, agent-to-agent via the MCP tools request_namespace_link /
|
|
1580
|
+
// respond_namespace_link (no CLI for that; see --help's CROSS-NAMESPACE
|
|
1581
|
+
// LINKS section).
|
|
1531
1582
|
const sub = process.argv[3];
|
|
1532
1583
|
if (sub === "set-project") {
|
|
1533
1584
|
const ns = process.argv[4];
|
|
1534
|
-
const project = process.argv[5];
|
|
1535
|
-
|
|
1585
|
+
const project = (process.argv[5] || "").startsWith("-") ? "" : (process.argv[5] || "");
|
|
1586
|
+
const doCreate = process.argv.includes("--create");
|
|
1587
|
+
if (!ns) { console.error("Usage: patchcord namespace set-project <namespace> [project-name] [--create]\n Omit project-name to un-group the namespace."); process.exit(1); }
|
|
1588
|
+
if (doCreate && !project) { console.error("--create needs a project name."); process.exit(1); }
|
|
1589
|
+
// Assignment RESOLVES an existing project and never creates one. The
|
|
1590
|
+
// server used to create a project for any unrecognised name, which turned
|
|
1591
|
+
// every typo into a new invisible project; --create makes creation an
|
|
1592
|
+
// explicit act instead of a side effect of misspelling.
|
|
1593
|
+
if (doCreate) {
|
|
1594
|
+
const { status: cStatus, json: cJson } = await accountCall("POST", "/api/projects", { name: project });
|
|
1595
|
+
if (cStatus === "201") console.log(` ${M.dim}created project "${project}"${M.rst}`);
|
|
1596
|
+
else if (cStatus === "409") console.log(` ${M.dim}project "${project}" already exists — assigning to it${M.rst}`);
|
|
1597
|
+
else { console.error(`could not create project (HTTP ${cStatus}): ${cJson?.error || ""}`); process.exit(1); }
|
|
1598
|
+
}
|
|
1536
1599
|
const { status, json } = await accountCall("POST", "/api/namespace/set-project", { namespace_id: ns, project: project || "" });
|
|
1537
|
-
if (status
|
|
1600
|
+
if (status === "404") {
|
|
1601
|
+
console.error(`No project named "${project}".`);
|
|
1602
|
+
console.error(` Create it first: patchcord project create ${project}`);
|
|
1603
|
+
console.error(` Or in one step: patchcord namespace set-project ${ns} ${project} --create`);
|
|
1604
|
+
process.exit(1);
|
|
1605
|
+
}
|
|
1606
|
+
if (status !== "200") { console.error(`set-project failed (HTTP ${status}): ${json?.error || ""}${json?.retryable ? " (transient — retry)" : ""}`); process.exit(1); }
|
|
1538
1607
|
if (json.status === "cleared") {
|
|
1539
|
-
console.log(`✓ ${ns} un-grouped — no project
|
|
1608
|
+
console.log(`✓ ${ns} un-grouped — belongs to no project, and its lead has no cross-team peers`);
|
|
1540
1609
|
} else {
|
|
1541
|
-
console.log(`✓ ${ns} assigned to project "${json.project}"
|
|
1610
|
+
console.log(`✓ ${ns} assigned to project "${json.project}"`);
|
|
1611
|
+
console.log(` ${M.dim}its LEAD can now message the leads of other Teams in this project;${M.rst}`);
|
|
1612
|
+
console.log(` ${M.dim}other agents still need an approved link (request_namespace_link)${M.rst}`);
|
|
1542
1613
|
}
|
|
1543
1614
|
process.exit(0);
|
|
1544
1615
|
}
|
|
1545
|
-
console.error("Usage: patchcord namespace set-project <namespace> [project-name]");
|
|
1616
|
+
console.error("Usage: patchcord namespace set-project <namespace> [project-name] [--create]");
|
|
1617
|
+
process.exit(1);
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// ── projects: the grouping entity above namespaces ──────────────────
|
|
1621
|
+
// Exists because the server deliberately does NOT create a project as a side
|
|
1622
|
+
// effect of assignment. Without a create/list path here, the only way to make
|
|
1623
|
+
// one was a raw API call — and without a LIST path, a mistyped project was
|
|
1624
|
+
// invisible, which is the exact defect that got an earlier version of this
|
|
1625
|
+
// feature abandoned.
|
|
1626
|
+
if (cmd === "project" || cmd === "projects") {
|
|
1627
|
+
const sub = process.argv[3] || "list";
|
|
1628
|
+
const fail = (status, json, what) => {
|
|
1629
|
+
const retry = json?.retryable ? " (transient — retry shortly, your login is fine)" : "";
|
|
1630
|
+
console.error(`${what} failed (HTTP ${status}): ${json?.error || ""}${retry}`);
|
|
1631
|
+
process.exit(1);
|
|
1632
|
+
};
|
|
1633
|
+
|
|
1634
|
+
if (sub === "list" || sub === "ls") {
|
|
1635
|
+
const { status, json } = await accountCall("GET", "/api/projects");
|
|
1636
|
+
if (status !== "200") fail(status, json, "project list");
|
|
1637
|
+
const projects = json?.projects || [];
|
|
1638
|
+
if (!projects.length) {
|
|
1639
|
+
console.log("No projects yet.");
|
|
1640
|
+
console.log(` ${M.dim}patchcord project create <name>${M.rst}`);
|
|
1641
|
+
process.exit(0);
|
|
1642
|
+
}
|
|
1643
|
+
for (const p of projects) {
|
|
1644
|
+
const members = (p.namespaces || []);
|
|
1645
|
+
console.log(`${M.green}${p.name}${M.rst} ${M.dim}${p.id}${M.rst}`);
|
|
1646
|
+
if (members.length) for (const ns of members) console.log(` · ${ns}`);
|
|
1647
|
+
else console.log(` ${M.dim}(no Teams assigned)${M.rst}`);
|
|
1648
|
+
}
|
|
1649
|
+
process.exit(0);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
if (sub === "create" || sub === "add") {
|
|
1653
|
+
const name = process.argv[4];
|
|
1654
|
+
if (!name) { console.error("Usage: patchcord project create <name>"); process.exit(1); }
|
|
1655
|
+
const { status, json } = await accountCall("POST", "/api/projects", { name });
|
|
1656
|
+
if (status === "409") { console.error(`A project named "${name}" already exists.`); process.exit(1); }
|
|
1657
|
+
if (status !== "201") fail(status, json, "project create");
|
|
1658
|
+
console.log(`✓ created project "${json.name}" ${M.dim}${json.id}${M.rst}`);
|
|
1659
|
+
console.log(` ${M.dim}patchcord namespace set-project <namespace> ${json.name}${M.rst}`);
|
|
1660
|
+
process.exit(0);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
if (sub === "rename" || sub === "mv") {
|
|
1664
|
+
const id = process.argv[4];
|
|
1665
|
+
const name = process.argv[5];
|
|
1666
|
+
if (!id || !name) { console.error("Usage: patchcord project rename <project-id> <new-name>\n Get the id from `patchcord project list`."); process.exit(1); }
|
|
1667
|
+
const { status, json } = await accountCall("PATCH", `/api/projects/${encodeURIComponent(id)}`, { name });
|
|
1668
|
+
if (status === "404") { console.error(`No project with id ${id}.`); process.exit(1); }
|
|
1669
|
+
if (status === "409") { console.error(`A project named "${name}" already exists.`); process.exit(1); }
|
|
1670
|
+
if (status !== "200") fail(status, json, "project rename");
|
|
1671
|
+
console.log(`✓ renamed to "${json.name}" ${M.dim}(membership and reach unchanged — this is only the label)${M.rst}`);
|
|
1672
|
+
process.exit(0);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
if (sub === "rm" || sub === "delete") {
|
|
1676
|
+
const id = process.argv[4];
|
|
1677
|
+
if (!id) { console.error("Usage: patchcord project rm <project-id>\n Get the id from `patchcord project list`."); process.exit(1); }
|
|
1678
|
+
const { status, json } = await accountCall("DELETE", `/api/projects/${encodeURIComponent(id)}`);
|
|
1679
|
+
if (status === "404") { console.error(`No project with id ${id}.`); process.exit(1); }
|
|
1680
|
+
if (status !== "200") fail(status, json, "project rm");
|
|
1681
|
+
const ungrouped = json?.ungrouped_namespaces || [];
|
|
1682
|
+
console.log(`✓ deleted project ${M.dim}${id}${M.rst}`);
|
|
1683
|
+
if (ungrouped.length) {
|
|
1684
|
+
// Deleting a project withdraws the lead-to-lead channel between exactly
|
|
1685
|
+
// these Teams. Fail-closed — reach is only ever removed here, never
|
|
1686
|
+
// widened — but it must be stated rather than discovered.
|
|
1687
|
+
console.log(` ${ungrouped.length} Team(s) un-grouped; their leads no longer reach each other:`);
|
|
1688
|
+
for (const ns of ungrouped) console.log(` · ${ns}`);
|
|
1689
|
+
} else {
|
|
1690
|
+
console.log(` ${M.dim}no Teams were assigned to it${M.rst}`);
|
|
1691
|
+
}
|
|
1692
|
+
process.exit(0);
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
console.error("Usage: patchcord project <list|create|rename|rm>");
|
|
1546
1696
|
process.exit(1);
|
|
1547
1697
|
}
|
|
1548
1698
|
|
|
@@ -1595,21 +1745,17 @@ if (cmd === "login" || cmd === "orchestrator" || cmd === "teamlead" || cmd === "
|
|
|
1595
1745
|
const project = flagVal("project", "");
|
|
1596
1746
|
const hostname = run("hostname -s") || run("hostname") || "unknown";
|
|
1597
1747
|
// is_lead: true always — the orchestrator IS the one identity per namespace
|
|
1598
|
-
// meant to coordinate across teams.
|
|
1599
|
-
// another namespace's lead after an approved namespace_links
|
|
1600
|
-
// agent via request_namespace_link/respond_namespace_link
|
|
1601
|
-
//
|
|
1748
|
+
// meant to coordinate across teams. Not harmless by itself any more: a lead
|
|
1749
|
+
// reaches another namespace's lead EITHER after an approved namespace_links
|
|
1750
|
+
// pair (agent-to-agent via request_namespace_link/respond_namespace_link) OR
|
|
1751
|
+
// when both namespaces sit in the same PROJECT, which needs no handshake.
|
|
1752
|
+
// So --project below is a reachability decision, not just a label.
|
|
1602
1753
|
const { status, json, m } = await accountCall("POST", "/api/provision", { namespace_id: ns, agent_id: "orchestrator", tool, role: "orchestrator", label: "orchestrator:self", is_lead: true });
|
|
1603
1754
|
if (status !== "200" || !json?.token) { console.error(`could not set up orchestrator (HTTP ${status}): ${json?.error || ""}`); process.exit(1); }
|
|
1604
1755
|
const base = String(json.url || `${m.baseUrl}/mcp`).replace(/\/mcp(\/bearer)?$/, "");
|
|
1605
1756
|
writeWorkerConfig(tool, root, base, json.token, hostname);
|
|
1606
1757
|
if (project) {
|
|
1607
|
-
|
|
1608
|
-
if (pStatus !== "200") {
|
|
1609
|
-
console.error(` ${M.dim}warning: orchestrator set up OK, but --project failed (HTTP ${pStatus}): ${pJson?.error || ""}${M.rst}`);
|
|
1610
|
-
} else {
|
|
1611
|
-
console.log(` ${M.dim}namespace ${ns} assigned to project "${project}"${M.rst}`);
|
|
1612
|
-
}
|
|
1758
|
+
await assignProject(ns, project, { warnOnly: true, label: "orchestrator set up OK" });
|
|
1613
1759
|
}
|
|
1614
1760
|
mkdirSync(join(root, ".patchcord"), { recursive: true });
|
|
1615
1761
|
const tj = join(root, ".patchcord", "team.json");
|
|
@@ -4034,5 +4180,5 @@ if (cmd === "skill") {
|
|
|
4034
4180
|
process.exit(0);
|
|
4035
4181
|
}
|
|
4036
4182
|
|
|
4037
|
-
console.error(`Unknown command: ${cmd}. Available: install, whoami, agents, upload, subscribe, update, login, provision, pull, orchestrator, team, schedule, --rename, --token, --agent-type, --version, --help`);
|
|
4183
|
+
console.error(`Unknown command: ${cmd}. Available: install, whoami, agents, upload, subscribe, update, login, provision, pull, orchestrator, team, project, namespace, schedule, --rename, --token, --agent-type, --version, --help`);
|
|
4038
4184
|
process.exit(1);
|
package/package.json
CHANGED
package/scripts/subscribe.mjs
CHANGED
|
@@ -617,7 +617,18 @@ function runOnce(ticket, baseUrl, getToken, refreshTicket) {
|
|
|
617
617
|
// Skip terminal resolved replies — they carry thread_resolved_at and need
|
|
618
618
|
// no action from the recipient. Notifying on them is the root cause of ack loops.
|
|
619
619
|
if (rec.thread_resolved_at) return;
|
|
620
|
-
|
|
620
|
+
// Qualify the sender when the message crosses a namespace boundary.
|
|
621
|
+
// A bare seat name is ambiguous the moment this agent is linked to two
|
|
622
|
+
// namespaces that share it, and `lead` is the seat name every team has.
|
|
623
|
+
// rec.namespace_id is OUR namespace here (the row is addressed to us);
|
|
624
|
+
// rec.from_namespace is the sender's. If either is missing we render
|
|
625
|
+
// bare rather than inventing an origin.
|
|
626
|
+
const fromAgent = rec.from_agent || "unknown";
|
|
627
|
+
const fromNs = rec.from_namespace;
|
|
628
|
+
const from =
|
|
629
|
+
fromNs && rec.namespace_id && fromNs !== rec.namespace_id
|
|
630
|
+
? `${fromAgent}@${fromNs}`
|
|
631
|
+
: fromAgent;
|
|
621
632
|
notify(`PATCHCORD: 1 new from ${from}`, { from, count: 1, kind: "message" });
|
|
622
633
|
});
|
|
623
634
|
|
package/skills/inbox/SKILL.md
CHANGED
|
@@ -51,6 +51,14 @@ If `subscribe_appears_down: true` is in the response, your subscribe.mjs was run
|
|
|
51
51
|
|
|
52
52
|
If there are pending messages, reply to all of them immediately. Do not ask the human first. Do not explain what you plan to reply. Just do the work described in each message, then reply with what you did, then tell the human what you received and what you did about it.
|
|
53
53
|
|
|
54
|
+
## Name the other agent when you talk to the human
|
|
55
|
+
|
|
56
|
+
When you tell a human that you sent, received, or replied to a message, always write the full address as `name@namespace` — never a bare role word like "the worker", "their lead", or "the team".
|
|
57
|
+
|
|
58
|
+
The human cannot see your inbox. An unnamed recipient is a claim they cannot check. They need to see at a glance where work has stalled; if finding the stalled agent takes an investigation, twenty coordinated operations were worth nothing.
|
|
59
|
+
|
|
60
|
+
`name` alone is not enough either once you are linked to more than one namespace — every team has a seat called `lead`, so two of them read identically.
|
|
61
|
+
|
|
54
62
|
## Sending
|
|
55
63
|
|
|
56
64
|
1. inbox() - clear any pending messages that block outbound sends. From the response, note `self_subscribed` (your own push-receiving state).
|