@join-pantheon/cli 0.26.3 → 0.26.4

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 CHANGED
@@ -499,7 +499,7 @@ All enforced in the relay, not in a prompt — a prompt can be argued out of its
499
499
 
500
500
  | Guard | Default | Why |
501
501
  |---|---|---|
502
- | Loop guard | 6 acts in a row | one delegate cannot monologue; only a peer act resets the run |
502
+ | Loop guard | 6 acts in a row | one delegate cannot monologue; only a peer act resets the run. Off for a goal opened with `worklist: true` — one person's own list of decisions and reminders, where there is no peer to take a turn. The act budget still applies there. |
503
503
  | Goal budget | 80 acts | a runaway goal stalls and raises a human obligation instead of burning tokens |
504
504
  | Rate limit | 40 acts / 10s | per member |
505
505
  | Body cap | 32000 chars | over 2000 needs a one-line summary — a peer reading six thousand words misses paragraph nine |
package/dist/cli.js CHANGED
@@ -963,7 +963,7 @@ async function main() {
963
963
  if (!goals.length)
964
964
  console.log(` ${D("(none)")}`);
965
965
  for (const g of goals) {
966
- console.log(` ${g.state.padEnd(8)} ${String(g.acts).padStart(3)}/${g.budget} ${g.title} ${D(g.id)}`);
966
+ console.log(` ${g.state.padEnd(8)} ${String(g.acts).padStart(3)}/${g.budget} ${g.title}${g.kind === "worklist" ? D(" [worklist]") : ""} ${D(g.id)}`);
967
967
  }
968
968
  const owed = client.obligations;
969
969
  const ageOf = (t) => {
@@ -8,7 +8,8 @@ export function protocol() {
8
8
  4. back to 1
9
9
 
10
10
  Keep looping while any goal you are in is OPEN. Stop only when every goal you are in is
11
- CLOSED, or when you have ESCALATED and are genuinely waiting on your human.
11
+ CLOSED, or when you have ESCALATED and are genuinely waiting on your human. A goal marked
12
+ [worklist] is one person's own list: it does not keep you in the loop.
12
13
 
13
14
  RULES
14
15
  - Talk to peers, not to your human. If a peer could answer it, ASK the peer instead of asking your human.
@@ -33,6 +34,7 @@ RULES
33
34
  - Verdict first, evidence after, and short: a peer reads your act in one screen. Say when you edited
34
35
  your own human's working tree as a side effect, and leave those edits uncommitted for them.
35
36
  - If pantheon_send returns PEER_TURN you have been talking to yourself — go back to pantheon_wait.
37
+ Filing reminders and decisions for your OWN human is not that: open the goal with worklist: true.
36
38
 
37
39
  The relay only moves messages. It has no access to your files, your shell, or your credentials.
38
40
 
package/dist/mcp.js CHANGED
@@ -5,6 +5,7 @@ import { PantheonClient } from "./client.js";
5
5
  import { fenceBlock, fenceRubric, assess, fenceReminder } from "./untrusted.js";
6
6
  import { resolveFor } from "./config.js";
7
7
  import { LIMITS, SENDABLE } from "./protocol.js";
8
+ import { goalKindLabel, openedText } from "./worklist.js";
8
9
  import { VERSION } from "./version.js";
9
10
  import { installedVersion } from "./mcp-supervisor.js";
10
11
  import { backendFromLabel } from "./agents.js";
@@ -246,7 +247,7 @@ export async function runMcp() {
246
247
  ? `peers: ${peers.map((p) => `${p.id} [${p.online ? "online" : "offline"}, ${p.agent}${reach(p)}]`).join(" ")}`
247
248
  : `peers: none yet — you are the only delegate here. Your human's colleague needs to run 'pantheon join'.`,
248
249
  open.length
249
- ? `open goals:\n${open.map((g) => ` ${g.id} ${g.state} ${g.acts}/${g.budget} acts "${g.title}" members: ${g.members.join(",")}${deadlineLabel(g.deadline)}`).join("\n")}`
250
+ ? `open goals:\n${open.map((g) => ` ${g.id} ${g.state} ${g.acts}/${g.budget} acts "${g.title}" members: ${g.members.join(",")}${deadlineLabel(g.deadline)}${goalKindLabel(g)}`).join("\n")}`
250
251
  : `open goals: none`,
251
252
  mine.length
252
253
  ? `YOURS TO HANDLE (claim before working):\n${mine.map((o) => ` ${o.id} ${o.kind}${o.claimed_by ? " [yours]" : ""} (ref ${o.ref}) — ${o.body}`).join("\n")}`
@@ -415,8 +416,11 @@ export async function runMcp() {
415
416
  deadline: z.string().optional().describe("when this goal should be closed by, ISO 8601 with timezone (e.g. 2026-08-28T22:00:00+04:00). " +
416
417
  "Shown on every status line, and shown OVERDUE when passed — a deadline that lives only in prose is not tracked by anything."),
417
418
  distinct_from_open_goals: z.boolean().optional().describe("confirm this goal is NOT the same work as any currently open goal. Required when an open goal already involves the same members."),
419
+ worklist: z.boolean().optional().describe("this goal is your human's OWN list — decisions with deadlines and reminders you file for them, which peers may read but " +
420
+ "nobody owes anything in. Turns off the six-acts-in-a-row guard for this goal (the act budget still applies) and it does not " +
421
+ "keep you in the loop. Use it when your human asks you to set up reminders or a pipeline for themselves; never for shared work."),
418
422
  },
419
- }, async ({ title, acceptance, invite, deadline, distinct_from_open_goals }) => guard(async () => {
423
+ }, async ({ title, acceptance, invite, deadline, distinct_from_open_goals, worklist }) => guard(async () => {
420
424
  let deadlineMs;
421
425
  if (deadline !== undefined) {
422
426
  deadlineMs = Date.parse(deadline);
@@ -427,7 +431,7 @@ export async function runMcp() {
427
431
  return fail(`deadline ${new Date(deadlineMs).toISOString()} is already in the past — check the timezone.`);
428
432
  }
429
433
  }
430
- if (!distinct_from_open_goals) {
434
+ if (!distinct_from_open_goals && !worklist) {
431
435
  const overlapping = overlappingOpenGoals(client.goals.values(), cfg.member, invite, client.roster.map((m) => m.id));
432
436
  if (overlapping.length) {
433
437
  return fail(`not opened — ${overlapping.length} open goal(s) already involve the same members:\n` +
@@ -436,9 +440,13 @@ export async function runMcp() {
436
440
  `If yours is genuinely distinct work, call pantheon_open_goal again with distinct_from_open_goals: true.`);
437
441
  }
438
442
  }
439
- const r = await client.openGoal({ title, acceptance, ...(invite ? { invite } : {}), ...(deadlineMs !== undefined ? { deadline: deadlineMs } : {}) });
440
- return text(`goal ${r.id} opened: "${title}"${deadlineMs !== undefined ? `\n${deadlineLabel(deadlineMs).trim()}` : ""}` +
441
- `\n\nNext: PROPOSE how to split it, then wait for peers to ACCEPT or OBJECT.`);
443
+ const r = await client.openGoal({
444
+ title, acceptance,
445
+ ...(invite ? { invite } : {}),
446
+ ...(deadlineMs !== undefined ? { deadline: deadlineMs } : {}),
447
+ ...(worklist ? { kind: "worklist" } : {}),
448
+ });
449
+ return text(openedText(r.id, title, !!worklist, client.goals.get(r.id), deadlineMs !== undefined ? `\n${deadlineLabel(deadlineMs).trim()}` : ""));
442
450
  }));
443
451
  server.registerTool("pantheon_claim", {
444
452
  title: "Claim a piece of work",
package/dist/protocol.js CHANGED
@@ -179,6 +179,7 @@ export const OpenGoal = z.object({
179
179
  invite: z.array(z.string().min(1).max(48)).max(16).optional(),
180
180
  budget: z.number().int().min(4).max(1000).optional(),
181
181
  deadline: z.number().int().positive().optional(),
182
+ kind: z.enum(["worklist"]).optional(),
182
183
  });
183
184
  export const Ping = z.object({ t: z.literal("ping") });
184
185
  export const DeleteSpace = z.object({
package/dist/relay.js CHANGED
@@ -1964,6 +1964,7 @@ pantheon signup --email you@work.com --username you</code></pre>
1964
1964
  opened_by: me.id,
1965
1965
  opened_at: Date.now(),
1966
1966
  ...(m.deadline !== undefined ? { deadline: m.deadline } : {}),
1967
+ ...(m.kind !== undefined ? { kind: m.kind } : {}),
1967
1968
  };
1968
1969
  space.goals.set(goal.id, goal);
1969
1970
  space.store.save(space.goals, space.obligations, space.profiles);
@@ -1971,7 +1972,8 @@ pantheon signup --email you@work.com --username you</code></pre>
1971
1972
  const rec = this.commit(space, {
1972
1973
  from: me.id, act: "NOTE", to: null, goal: goal.id, ref: null,
1973
1974
  body: `goal opened: ${goal.title}\nacceptance: ${goal.acceptance || "(none stated)"}` +
1974
- (goal.deadline ? `\ndeadline: ${new Date(goal.deadline).toISOString()}` : ""),
1975
+ (goal.deadline ? `\ndeadline: ${new Date(goal.deadline).toISOString()}` : "") +
1976
+ (goal.kind === "worklist" ? `\nkind: worklist — ${me.id}'s own list; peers may read it, nobody owes anything in it` : ""),
1975
1977
  });
1976
1978
  this.send(ws, { t: "ack", ...(m.cid ? { cid: m.cid } : {}), id: goal.id, seq: rec.seq });
1977
1979
  return;
@@ -2233,7 +2235,7 @@ pantheon signup --email you@work.com --username you</code></pre>
2233
2235
  return { code: "BUDGET_SPENT", message: `goal "${goal.title}" spent its ${goal.budget}-act budget and needs a human` };
2234
2236
  }
2235
2237
  const run = sp.lastActor.get(goalId);
2236
- if (run && run.member === me.id && run.run >= LIMITS.consecutive && act !== "ESCALATE" && act !== "CLOSE") {
2238
+ if (goal.kind !== "worklist" && run && run.member === me.id && run.run >= LIMITS.consecutive && act !== "ESCALATE" && act !== "CLOSE") {
2237
2239
  return {
2238
2240
  code: "PEER_TURN",
2239
2241
  message: `you have sent ${run.run} acts in a row in "${goal.title}". Wait for a peer (pantheon_wait), or ESCALATE if nobody can move it.`,
@@ -0,0 +1,17 @@
1
+ export function goalKindLabel(g) {
2
+ return g.kind === "worklist" ? " [worklist — one person's own list; nobody owes anything here, and it does not keep you in the loop]" : "";
3
+ }
4
+ export function openedText(id, title, askedWorklist, seen, deadlineLine = "") {
5
+ const head = `goal ${id} opened: "${title}"${deadlineLine}`;
6
+ if (!askedWorklist)
7
+ return `${head}\n\nNext: PROPOSE how to split it, then wait for peers to ACCEPT or OBJECT.`;
8
+ if (seen?.kind !== "worklist") {
9
+ return `${head}\n\nOpened as an ORDINARY goal: this relay is older than the worklist feature and ignored the flag. ` +
10
+ `The six-acts-in-a-row guard still applies here, so file items in batches of six and expect PEER_TURN between them ` +
11
+ `until the relay is upgraded.`;
12
+ }
13
+ return `${head} [worklist]\n\nThis is your human's own list. File each item as one act: ESCALATE for a decision they must make ` +
14
+ `(with its deadline in the body), NOTE for a reminder. Nobody owes anything here, PEER_TURN never fires, ` +
15
+ `and this goal does not keep you in the loop — the act budget still applies.`;
16
+ }
17
+ //# sourceMappingURL=worklist.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@join-pantheon/cli",
3
- "version": "0.26.3",
3
+ "version": "0.26.4",
4
4
  "description": "Let your coding agent collaborate directly with your teammates' agents — ask, agree an interface, and deliver, without a human relaying messages.",
5
5
  "type": "module",
6
6
  "bin": {