@orlan-maker/cli 0.4.0 → 0.5.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.
package/README.md CHANGED
@@ -102,7 +102,10 @@ output.
102
102
 
103
103
  `orlan brief` is for the start of a session. It prints the topic, the open requests, the files with
104
104
  their current versions, and one `next_step` line, in about 500 tokens for 6 files and 3 requests. The
105
- topic is the one the agent used last, else its only topic. `orlan files add` posts a new file to the
105
+ topic is the one the person has open in Orlan now ("You are in "startups" (open in Orlan now)"). When the
106
+ agent cannot reach that topic, the brief says so, gives the step that grants it, and names the topic it
107
+ works in instead: the newer of the one it used last and the one the person opened last, else its only
108
+ topic. Every command with no `--topic` uses the same topic. `orlan files add` posts a new file to the
106
109
  topic and puts it on the board, in one request. Both are plain HTTP calls with the agent token.
107
110
 
108
111
  `orlan board` prints the board of the topic. Each item shows its id, type, place and size in board
package/dist/commands.js CHANGED
@@ -82,12 +82,16 @@ function finish(io, values, data, lines, next) {
82
82
  const topicInput = (values) => (typeof values.topic === "string" ? { topicId: values.topic } : {});
83
83
  /**
84
84
  * The topic of a command that needs one: --topic (an id or a name), else the topic the brief names (the
85
- * one the agent used last, else its only topic).
85
+ * one the person has open in Orlan now, else the one the agent used last, else its only topic). When the
86
+ * person's open topic is out of the agent's reach, the command says so first (F123), not with --json.
86
87
  */
87
- async function topicOrDefault(api, values) {
88
+ async function topicOrDefault(api, values, io) {
88
89
  if (typeof values.topic === "string")
89
90
  return values.topic;
90
- const { topic } = await api.get("/api/agent/brief", {}, "the brief");
91
+ const { topic, notice } = await api.get("/api/agent/brief", {}, "the brief");
92
+ if (notice && !values.json)
93
+ for (const line of notice)
94
+ io.out(line);
91
95
  if (!topic) {
92
96
  throw new OrlanError("The agent has several topics and used none yet. Add --topic <topic>.", "topic_missing");
93
97
  }
@@ -251,6 +255,20 @@ async function confirmPrinted(server, token, io, deliveries) {
251
255
  }
252
256
  }
253
257
  }
258
+ /**
259
+ * "all topics", the restricted topics it also reaches and the ones it leaves out (B058), or the topic
260
+ * names. An older server sends no leftOut.
261
+ */
262
+ const reachText = (scope, all) => {
263
+ if (!scope.allTopics)
264
+ return scope.topics.map((topic) => quote(topic.name)).join(", ");
265
+ const named = (topics) => topics.map((topic) => `${quote(topic.name)} (restricted)`).join(", ");
266
+ const included = scope.topics.filter((topic) => topic.restricted);
267
+ const leftOut = scope.leftOut ?? [];
268
+ return (all +
269
+ (included.length > 0 ? `, and ${named(included)}` : "") +
270
+ (leftOut.length > 0 ? `, except ${named(leftOut)}` : ""));
271
+ };
254
272
  /** Prints what planOldInstall removed, on one line, and the commands that remove the rest by hand. */
255
273
  function printRemoved(io, { removed, byHand }) {
256
274
  if (removed.length > 0)
@@ -285,7 +303,7 @@ async function connect(agent, values, io) {
285
303
  await writeConfig(config);
286
304
  const role = made.token.role[0]?.toUpperCase() + made.token.role.slice(1);
287
305
  io.out(`Made an agent token for ${agentLabels[agent]}: ${made.token.prefix}..., ${role} on ` +
288
- `${made.token.allTopics ? "all topics" : made.token.topics.map((topic) => quote(topic.name)).join(", ")}. It is in the ${where === "keychain" ? "keychain" : "credentials file"}.`);
306
+ `${reachText(made.token, "all topics")}. It is in the ${where === "keychain" ? "keychain" : "credentials file"}.`);
289
307
  await writeSkills(agent);
290
308
  io.out(`Installed the Orlan skills orlan, orlan-review and orlan-versions in ${skillsDir(agent)}.`);
291
309
  // The test is the person's, not a call of the agent: it names no agent session.
@@ -344,7 +362,7 @@ export const commands = {
344
362
  details: [
345
363
  "Shows a code and opens the Orlan page that approves it. Sign in there, check that the code is",
346
364
  "the same, choose the organisation, and what your agents get: one topic, or all topics of the",
347
- "organisation (also the topics made later; restricted topics only when you tick them in Details).",
365
+ "organisation (also the topics made later; restricted topics only when you include them there).",
348
366
  "Details also has the agent role. The CLI token goes to the OS keychain, or to a file only you can",
349
367
  "read when there is no keychain.",
350
368
  "",
@@ -493,9 +511,7 @@ export const commands = {
493
511
  io.out(`Server: ${config.server}`);
494
512
  io.out(`Signed in as: ${quote(status.user.name)} (${status.user.email ?? "guest account"})`);
495
513
  io.out(`Organisation: ${quote(status.org.name)} (${status.org.role})`);
496
- io.out(`New agents get: ${status.agentDefaults.role} on ${status.agentDefaults.allTopics
497
- ? "all topics, also new ones"
498
- : status.agentDefaults.topics.map((topic) => quote(topic.name)).join(", ") || "no topics (use --topic)"}`);
514
+ io.out(`New agents get: ${status.agentDefaults.role} on ${reachText(status.agentDefaults, "all topics, also new ones") || "no topics (use --topic)"}`);
499
515
  if (agents.length === 0)
500
516
  io.out("Agents: none connected.");
501
517
  for (const { agent, token: local, role, check } of agents) {
@@ -536,8 +552,9 @@ export const commands = {
536
552
  "",
537
553
  AGENT_HELP,
538
554
  "--topic <id> A topic the agent can use. Repeat it for more. The agent then gets only these topics.",
539
- " Default: what you chose at sign-in (one topic, the ticked topics, or all topics).",
540
- "--role <role> editor, commenter or viewer. Default: the role you chose at sign-in.",
555
+ " Each must be in what you approved at sign-in: a restricted topic only when you",
556
+ " included it. Default: what you chose at sign-in (one topic, the ticked topics, or all topics).",
557
+ "--role <role> editor, commenter or viewer, not above the role you approved. Default: that role.",
541
558
  ],
542
559
  options: CONNECT_OPTIONS,
543
560
  positionals: [0, 0],
@@ -574,14 +591,14 @@ export const commands = {
574
591
  usage: "orlan files list [--topic <topic>] [--agent <id>] [--json]",
575
592
  summary: "List the files of a topic with their current versions.",
576
593
  details: [
577
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
594
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
578
595
  AGENT_TOKEN_HELP,
579
596
  JSON_HELP,
580
597
  ],
581
598
  options: { ...agentOption, ...jsonOption, topic: { type: "string" } },
582
599
  positionals: [0, 0],
583
600
  run: (values, _positionals, io) => withAgent(values, async (api) => {
584
- const topicId = await topicOrDefault(api, values);
601
+ const topicId = await topicOrDefault(api, values, io);
585
602
  const { files } = await api.call("read_board", { topicId, view: "files" });
586
603
  return finish(io, values, { files }, files.length === 0
587
604
  ? ["No files."]
@@ -601,7 +618,7 @@ export const commands = {
601
618
  "",
602
619
  "--at <x,y> Put it at this point of the board, in board coordinates, or at the nearest free",
603
620
  " place. `orlan board` shows where the items are.",
604
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
621
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
605
622
  AGENT_TOKEN_HELP,
606
623
  JSON_HELP,
607
624
  ],
@@ -611,7 +628,7 @@ export const commands = {
611
628
  const at = numbersOption(values, "at", 2);
612
629
  if (at) {
613
630
  // A place on the board: the file goes up first, then the post places it.
614
- const topicId = await topicOrDefault(api, values);
631
+ const topicId = await topicOrDefault(api, values, io);
615
632
  const uploadId = await api.upload(await readFile(filePath), { topic: topicId });
616
633
  const posted = await api.call("post", { topicId, name: path.basename(filePath), uploadId, position: { x: at[0], y: at[1] } });
617
634
  return finish(io, values, {
@@ -889,7 +906,7 @@ export const commands = {
889
906
  "--page <n> The page, from 1.",
890
907
  "--region <x,y,w,h> The rectangle on the page, as fractions (0 to 1). Default: the whole page.",
891
908
  "--at <x,y> A new thread on this point of the board, in board coordinates.",
892
- "--topic <topic> The topic of --at, of a #12 or of a file name. Default: the topic you used last.",
909
+ "--topic <topic> The topic of --at, of a #12 or of a file name. Default: the topic open in Orlan now, else the one used last.",
893
910
  AGENT_TOKEN_HELP,
894
911
  JSON_HELP,
895
912
  ],
@@ -985,14 +1002,14 @@ export const commands = {
985
1002
  '"in frame <id>". Each box is the box after it grew to fit its words. People vote; an agent reads',
986
1003
  "the vote and its result, it does not vote.",
987
1004
  "",
988
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1005
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
989
1006
  AGENT_TOKEN_HELP,
990
1007
  JSON_HELP,
991
1008
  ],
992
1009
  options: { ...agentOption, ...jsonOption, topic: { type: "string" } },
993
1010
  positionals: [0, 0],
994
1011
  run: (values, _positionals, io) => withAgent(values, async (api) => {
995
- const topicId = await topicOrDefault(api, values);
1012
+ const topicId = await topicOrDefault(api, values, io);
996
1013
  // Two requests at the same time: the board, and the names of its files.
997
1014
  const [board, { files }] = await Promise.all([
998
1015
  api.call("read_board", { topicId, view: "board" }),
@@ -1054,7 +1071,7 @@ export const commands = {
1054
1071
  "",
1055
1072
  "--out <file.png> Where to save the picture. A file that is there is replaced.",
1056
1073
  "--frame <frame> Only this frame: its id, from `orlan board`.",
1057
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1074
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1058
1075
  AGENT_TOKEN_HELP,
1059
1076
  JSON_HELP,
1060
1077
  ],
@@ -1070,7 +1087,7 @@ export const commands = {
1070
1087
  if (typeof values.out !== "string" || !values.out) {
1071
1088
  throw new OrlanError("Add --out <file.png>: where to save the picture.", undefined, "orlan board view --out board.png");
1072
1089
  }
1073
- const topicId = await topicOrDefault(api, values);
1090
+ const topicId = await topicOrDefault(api, values, io);
1074
1091
  const answer = await api.call("view_board", { topicId, ...(typeof values.frame === "string" ? { frameId: values.frame } : {}) });
1075
1092
  const saved = path.resolve(values.out);
1076
1093
  const png = Buffer.from(answer.png, "base64");
@@ -1130,7 +1147,7 @@ export const commands = {
1130
1147
  "--frame <frame> The frame the item goes in, by its id. none: in no frame. Default: the frame that",
1131
1148
  " holds more than half of it.",
1132
1149
  '--text <text> The text, as the "<text>" word gives it. For an arrow: its label, for example "yes".',
1133
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1150
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1134
1151
  AGENT_TOKEN_HELP,
1135
1152
  JSON_HELP,
1136
1153
  ],
@@ -1198,7 +1215,7 @@ export const commands = {
1198
1215
  // The server refuses a frame on an arrow, and says why.
1199
1216
  Object.assign(edit, frameOption(values));
1200
1217
  return withAgent(values, async (api) => {
1201
- const { items, warnings } = await editBoard(api, values, [edit]);
1218
+ const { items, warnings } = await editBoard(api, values, io, [edit]);
1202
1219
  const item = items[0];
1203
1220
  const where = type === "arrow" ? `, from ${values.from} to ${values.to}` : "";
1204
1221
  return finish(io, values, { ...item, warnings }, [`Added ${boxText(item)}${where}.`, ...warningLines(warnings)], afterWarnings(warnings, type === "arrow"
@@ -1233,7 +1250,7 @@ export const commands = {
1233
1250
  "--to <item> The item the arrow points to, as --from.",
1234
1251
  "--frame <frame> Put the item in this frame, by its id. none: take it out of its frame. The item",
1235
1252
  " stays where it is. With --at and no --frame, the item goes in the frame it lands in.",
1236
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1253
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1237
1254
  AGENT_TOKEN_HELP,
1238
1255
  JSON_HELP,
1239
1256
  ],
@@ -1272,7 +1289,7 @@ export const commands = {
1272
1289
  throw new OrlanError("Give --text, --at, --size, --text-color, --kind, --color, --from, --to or --frame.", undefined, `orlan board change ${id} --text "<text>"`);
1273
1290
  }
1274
1291
  return withAgent(values, async (api) => {
1275
- const { items, warnings } = await editBoard(api, values, edits);
1292
+ const { items, warnings } = await editBoard(api, values, io, edits);
1276
1293
  const item = items.find((each) => each.id === id);
1277
1294
  return finish(io, values, { ...(item ?? { id }), warnings }, [item ? `Changed ${boxText(item)}.` : `Changed ${id}.`, ...warningLines(warnings)], afterWarnings(warnings, "orlan board (the board with the change)"));
1278
1295
  });
@@ -1287,14 +1304,14 @@ export const commands = {
1287
1304
  "of a deleted frame stay on the board, in the frame that frame was in.",
1288
1305
  "",
1289
1306
  "<item> The item id, from `orlan board`. Give several to delete several.",
1290
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1307
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1291
1308
  AGENT_TOKEN_HELP,
1292
1309
  JSON_HELP,
1293
1310
  ],
1294
1311
  options: { ...agentOption, ...jsonOption, topic: { type: "string" } },
1295
1312
  positionals: [1, 100],
1296
1313
  run: (values, ids, io) => withAgent(values, async (api) => {
1297
- const { warnings } = await editBoard(api, values, ids.map((id) => ({ op: "delete", id })));
1314
+ const { warnings } = await editBoard(api, values, io, ids.map((id) => ({ op: "delete", id })));
1298
1315
  return finish(io, values, { deleted: ids, warnings }, [
1299
1316
  `Deleted ${ids.length === 1 ? "1 item" : `${ids.length} items`}: ${ids.join(", ")}. A person can undo it.`,
1300
1317
  ...warningLines(warnings),
@@ -1335,7 +1352,7 @@ export const commands = {
1335
1352
  "the error says what to change. The answer gives each item's id and its final place and size.",
1336
1353
  ...WARNINGS_HELP,
1337
1354
  "",
1338
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1355
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1339
1356
  AGENT_TOKEN_HELP,
1340
1357
  JSON_HELP,
1341
1358
  ],
@@ -1353,7 +1370,7 @@ export const commands = {
1353
1370
  throw new OrlanError('The edits are a JSON list, for example [{"op":"delete","id":"<item>"}].', undefined, "orlan board edit --help");
1354
1371
  }
1355
1372
  return withAgent(values, async (api) => {
1356
- const { ids, items, warnings } = await editBoard(api, values, edits);
1373
+ const { ids, items, warnings } = await editBoard(api, values, io, edits);
1357
1374
  return finish(io, values, { ids, items, warnings }, [
1358
1375
  `Made ${ids.length} change${ids.length === 1 ? "" : "s"} in one step.`,
1359
1376
  ...items.map((item) => `- ${boxText(item)}`),
@@ -1401,7 +1418,7 @@ export const commands = {
1401
1418
  "",
1402
1419
  "<file.mmd> The Mermaid file.",
1403
1420
  "--frame <frame> Draw the diagram in this frame, by its id, from `orlan board`.",
1404
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1421
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1405
1422
  AGENT_TOKEN_HELP,
1406
1423
  JSON_HELP,
1407
1424
  ],
@@ -1411,7 +1428,7 @@ export const commands = {
1411
1428
  const source = await readFile(file, "utf8").catch((error) => {
1412
1429
  throw new OrlanError(`Orlan cannot read ${quote(file)}: ${error.code ?? error.message}.`, undefined, "give the path of a Mermaid file, for example orlan board mermaid flow.mmd");
1413
1430
  });
1414
- const topicId = await topicOrDefault(api, values);
1431
+ const topicId = await topicOrDefault(api, values, io);
1415
1432
  const answer = await api.call("import_mermaid", {
1416
1433
  topicId,
1417
1434
  mermaid: source,
@@ -1454,7 +1471,7 @@ export const commands = {
1454
1471
  "--assignee <who> me (this agent), user:<id> or agent:<id>. Default: nobody.",
1455
1472
  "--thread <t> The comment thread the task comes from: #12 or the thread id.",
1456
1473
  "--done The task is done already.",
1457
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1474
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1458
1475
  AGENT_TOKEN_HELP,
1459
1476
  JSON_HELP,
1460
1477
  ],
@@ -1471,7 +1488,7 @@ export const commands = {
1471
1488
  const assignee = assigneeOption(config, values);
1472
1489
  const task = await api.call("record", {
1473
1490
  kind: "task",
1474
- topicId: await topicOrDefault(api, values),
1491
+ topicId: await topicOrDefault(api, values, io),
1475
1492
  text,
1476
1493
  ...(assignee ? { assignee } : {}),
1477
1494
  ...(typeof values.thread === "string" ? { sourceThreadId: values.thread } : {}),
@@ -1525,7 +1542,7 @@ export const commands = {
1525
1542
  "",
1526
1543
  "--body <text> The decision in full: what, and why.",
1527
1544
  "--thread <t> The comment thread the decision comes from: #12 or the thread id.",
1528
- "--topic <topic> The topic id or its name. Default: the topic the agent used last, else its only topic.",
1545
+ "--topic <topic> The topic id or its name. Default: the topic open in Orlan now, else the one used last.",
1529
1546
  AGENT_TOKEN_HELP,
1530
1547
  JSON_HELP,
1531
1548
  ],
@@ -1540,7 +1557,7 @@ export const commands = {
1540
1557
  run: (values, [title], io) => withAgent(values, async (api) => {
1541
1558
  const decision = await api.call("record", {
1542
1559
  kind: "decision",
1543
- topicId: await topicOrDefault(api, values),
1560
+ topicId: await topicOrDefault(api, values, io),
1544
1561
  title,
1545
1562
  ...(typeof values.body === "string" ? { body: values.body } : {}),
1546
1563
  ...(typeof values.thread === "string" ? { sourceThreadId: values.thread } : {}),
@@ -1602,8 +1619,12 @@ export const commands = {
1602
1619
  usage: "orlan brief [--topic <topic>] [--agent <id>] [--json]",
1603
1620
  summary: "Print where the work stands: the topic, the open requests, the files, and the next step.",
1604
1621
  details: [
1605
- "For the start of a session: one short answer, in one plain HTTP call. The topic is the one the agent",
1606
- "used last, else its only topic. It lists the open requests (`orlan inbox` prints them in full),",
1622
+ "For the start of a task: one short answer, in one plain HTTP call. The topic is the one the person",
1623
+ "has open in Orlan now, and the first lines say so. When the agent cannot reach that topic, they say",
1624
+ "so, give the step that grants it, and name the topic the agent works in instead: the newer of the",
1625
+ "one it used last and the one the person opened last, else its only topic. Other commands with no",
1626
+ "--topic use the same topic; in one session they keep the topic of the last call for 5 minutes.",
1627
+ "It lists the open requests (`orlan inbox` prints them in full),",
1607
1628
  "the files with their current versions, the open vote and the open tasks (one line each), and one",
1608
1629
  "next_step line. People vote; an agent reads the vote, it does not vote.",
1609
1630
  "",
@@ -1614,7 +1635,9 @@ export const commands = {
1614
1635
  options: { ...agentOption, ...jsonOption, topic: { type: "string" } },
1615
1636
  positionals: [0, 0],
1616
1637
  run: (values, _positionals, io) => withAgent(values, async (api) => {
1617
- const { lines, nextStep, ...answer } = await api.get("/api/agent/brief", { topic: values.topic }, "the brief");
1638
+ const { lines, nextStep, ...answer } = await api.get("/api/agent/brief",
1639
+ // The start of a task: Orlan takes the topic the person has open now again (F123).
1640
+ { topic: values.topic, start: "true" }, "the brief");
1618
1641
  // The lines end with Orlan's next_step line.
1619
1642
  io.out(values.json ? JSON.stringify({ ...answer, next_step: nextStep }) : lines.join("\n"));
1620
1643
  return 0;
@@ -1771,9 +1794,9 @@ export const commands = {
1771
1794
  },
1772
1795
  };
1773
1796
  /** Runs edit_board on the topic of --topic, else the default topic: one step, all edits or none. */
1774
- async function editBoard(api, values, edits) {
1797
+ async function editBoard(api, values, io, edits) {
1775
1798
  const answer = await api.call("edit_board", {
1776
- topicId: await topicOrDefault(api, values),
1799
+ topicId: await topicOrDefault(api, values, io),
1777
1800
  edits,
1778
1801
  });
1779
1802
  // A server before F096 gives no warnings.
package/dist/http.js CHANGED
@@ -25,6 +25,7 @@ const explained = {
25
25
  login_expired: "The sign-in code expired. Run `orlan auth login` again.",
26
26
  login_used: "This sign-in code was already used. Run `orlan auth login` again.",
27
27
  login_rate_limited: "Too many sign-ins from this computer in a short time. Wait 10 minutes, then try again.",
28
+ agent_scope_exceeded: "The agent asks for more than the person approved for this CLI: a topic or a role outside the approval. orlan connect can only narrow the access.",
28
29
  pair_invalid: "Orlan does not know this --pair id. Copy the prompt again from the Connect dialog.",
29
30
  pair_expired: "The --pair id expired. It works for 10 minutes. Copy the prompt again from the Connect dialog.",
30
31
  pair_used: "Another CLI used this --pair id already. It works for one sign-in. Copy the prompt again from the Connect dialog.",
@@ -47,6 +48,7 @@ const nextSteps = {
47
48
  login_expired: "orlan auth login",
48
49
  login_used: "orlan auth login",
49
50
  login_rate_limited: "wait 10 minutes, then orlan auth login",
51
+ agent_scope_exceeded: "ask your person to approve the access in Orlan: they run orlan auth login and include the topic there",
50
52
  pair_invalid: "copy the prompt again from the Connect dialog in Orlan, or run orlan auth login",
51
53
  pair_expired: "copy the prompt again from the Connect dialog in Orlan, or run orlan auth login",
52
54
  pair_used: "copy the prompt again from the Connect dialog in Orlan, or run orlan auth login",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orlan-maker/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "The orlan command: connect Claude Code, Codex, Cursor or OpenCode to Orlan with a token and skills, and work with its topics, files and comments from the terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: orlan
3
- description: Orlan is connected. This skill is installed only when the person connected this agent to Orlan, the shared board of their team and its AI agents. Use it first, before any other diagram skill, when the person asks for a diagram, a flowchart, an architecture or a map of a system. Also use it, without being asked to draw, when the person asks you to explain, compare or design a system, an architecture, a flow or a process with parts and links ("explain how a CDN works", "monolith vs microservices"): answer in the chat and draw it on the board too. On Orlan a diagram is shapes and labeled arrows on the board, not an HTML, SVG or image file. Also use it when the person says the canvas, the board, the topic, "in Orlan" or "on Orlan", asks what is on the board, asks for a page, deck, mock or other file for people to see or review, or names a comment, a version or a request on Orlan. Do not use it for a short fact answer, a sum, a question on code, or a fix in a local file that the person names.
3
+ description: Orlan is connected: the shared board of the person's team and its agents; the person connected you. Use it first, before any other diagram skill, for a diagram, a flowchart, an architecture or a map of a system. Also use it, without being asked to draw, when the person asks you to explain, compare or design a system, a flow or a process with parts and links ("explain how a CDN works"): answer in the chat and draw it on the board too. When the person asks to put an explanation, a plan, a guide or a summary in Orlan, build it on the board as a diagram and short notes, not as an HTML file. On Orlan a diagram is shapes and labeled arrows, not an HTML, SVG or image file. Also use it when the person says the canvas, the board, the topic, "in Orlan" or "on Orlan", asks what is on the board, asks for a page, deck, mock or file to review, or names a comment, a version or a request on Orlan. Do not use it for a short fact answer, a sum, a question on code, or a fix in a local file that the person names.
4
4
  ---
5
5
 
6
6
  # Orlan
@@ -23,8 +23,11 @@ When Orlan is connected, these words mean the Orlan topic. Do not ask which one
23
23
  name or type. A path such as `./notes.txt` is a local file.
24
24
  - "the comments", "the feedback", "the review" - the open threads on the topic.
25
25
 
26
- `orlan brief` names your topic. With one topic, it is the one. With more, it is the one you used last,
27
- or the one the person names.
26
+ Your topic is the one the person has open in Orlan now. Run `orlan brief` at the start of each Orlan
27
+ task: it names the topic ("You are in "startups" (open in Orlan now)"), and every command with no
28
+ `--topic` works there. Do not ask which topic, and do not pick another one. When the person names a
29
+ topic, use `--topic <topic>`. When the brief says the person's open topic is out of your reach, tell
30
+ the person, with the step the brief gives, before you work in another topic.
28
31
 
29
32
  ## When to use Orlan
30
33
 
@@ -38,16 +41,45 @@ or the one the person names.
38
41
  "design a payment flow"): answer in the chat, and also draw it on the board. Do not ask first, and do
39
42
  not wait for the word "Orlan" or "board". End the answer with one line that says where the drawing
40
43
  is: the topic and the frame. A short fact answer ("what port does HTTPS use") stays in the chat.
44
+ - The person asks you to put an explanation, a plan, a guide or a summary in Orlan ("put all of this in
45
+ Orlan", "put it on the board"): build it on the board. Follow "Put it in Orlan" below. No HTML file.
41
46
  - The person asks for a note, a text, a shape, a frame or an arrow on the board: `orlan board add`.
42
47
  Change one with `orlan board change <item>`, delete one with `orlan board delete <item>`.
43
- - The person asks you to make something else that people look at: a page, a mock, a deck, a report, a
44
- chart. Make the file, check it, then post it to the topic:
48
+ - The person asks for a page, a document, a deck, a mock, a report or a chart as a file: make the file,
49
+ check it, then post it to the topic:
45
50
  `orlan files add <path>`. When a local rule says to keep visuals as local files, keep the local file
46
- and post it too. Tell the person that it is on the board, and give its name and version.
51
+ and post it too. Tell the person that it is on the board, and give its name and version. Make a
52
+ file only when the person asks for one, or for long prose that people read as a document.
47
53
  - The person asks you to change a file that is on the topic: pull it with `--edit`, change it, and post
48
54
  a new version: `orlan files push <file> <path> --changelog "<what changed>"`.
49
55
  - A comment or a request names you: follow the `orlan-review` skill.
50
56
 
57
+ ## Put it in Orlan
58
+
59
+ "Put all of this in Orlan" after an explanation, a plan, a guide or a summary means: build it on the
60
+ board, so that people get it at a glance. An HTML file is a tab that people must open; the board is
61
+ what they see.
62
+
63
+ 1. `orlan brief` for the topic, and `orlan board` for a free place (right of or below the items).
64
+ 2. Cut the content into 2 to 5 parts. Each part gets one frame, with the part's name as its title, in
65
+ one row from left to right.
66
+ 3. The structure (steps, a flow, a decision, parts and their links) is a diagram in its own frame, drawn
67
+ as in "Draw a diagram".
68
+ 4. The key points are short notes in the frame of their part: one point in each note, at most 20 words,
69
+ 3 to 6 notes in a frame. Make a frame and its notes in one `orlan board edit` step. A frame of
70
+ `40 + 210 * columns` by `80 + 140 * rows`, and each note (190 x 120) at
71
+ `20 + 210 * column`, `60 + 140 * row` from the frame's corner, with `"frame"` set to the frame's id:
72
+ `[{"op":"create","type":"frame","id":"money","x":0,"y":0,"w":460,"h":220,"text":"Money"},`
73
+ `{"op":"create","type":"note","x":20,"y":60,"text":"Keep 6 months of costs in the bank","frame":"money"},`
74
+ `{"op":"create","type":"note","x":230,"y":60,"text":"Pay yourself last","frame":"money"}]`
75
+ 5. Read the warnings and fix them. Look at it: `orlan board view --out <file.png>`, open the picture.
76
+ 6. End your answer with one line that names the topic and the frames: "I put it on the board of
77
+ "startups", in the frames "Basics", "Money" and "First steps"."
78
+
79
+ Do not post an HTML file or a document for this. Post a file only when the person asks for a page, a
80
+ document, a deck or a mock, or when the content is long prose that people read as a document. Never
81
+ make both a board version and a file, unless the person asks for both.
82
+
51
83
  ## Draw a diagram
52
84
 
53
85
  A diagram on Orlan is board shapes with words and labeled arrows. Do not post an HTML file or notes as a
@@ -162,8 +194,13 @@ Run `orlan <command> --help` for the options of a command.
162
194
  the board. No HTML file, no notes.
163
195
  - "explain how a CDN works" - explain it in the chat, draw the parts and their links in a frame as in
164
196
  "Draw a diagram", and end with one line: "I drew it on the board of <topic>, in the frame <title>."
165
- - "put the notes on the board" - post the notes as a file, or add them as a note:
166
- `orlan board add note "<text>" --at <x,y>`, at a free place that `orlan board` shows.
197
+ - "put all of this in Orlan", after you explained how to start a company - follow "Put it in Orlan":
198
+ a frame for each part, a diagram of the steps, short notes for the key points, in the topic the brief
199
+ names. No HTML file. End with the topic and the frames.
200
+ - "put the notes on the board" - add them as short notes in a frame, as in "Put it in Orlan", at a free
201
+ place that `orlan board` shows.
202
+ - "make a one-page HTML guide of this for the team" - the person asks for a page: make the file and
203
+ post it with `orlan files add <path>`. No board version.
167
204
  - "what is 17*23?" - answer 391. No Orlan call.
168
205
  - "fix the typo in ./notes.txt" - fix the local file. No Orlan call.
169
206
 
@@ -21,7 +21,7 @@ description: Get a file from Orlan and post a new version of it with a changelog
21
21
  It ends your claim. When a version landed after the one you pulled, Orlan refuses it with
22
22
  `stale_base` and that version's changelog: pull the newest version, make your change on it, push again.
23
23
  - `orlan files add <path>` - posts a local file as a new file on your topic and puts it on the board.
24
- `--topic <topic>` names the topic; the default is the topic you used last. `--at <x,y>` puts it at
24
+ `--topic <topic>` names the topic; the default is the topic the person has open in Orlan. `--at <x,y>` puts it at
25
25
  that point of the board (`orlan board` shows where the items are).
26
26
  - `orlan files rollback <file> --version 3 --changelog "<why>"` - posts an older version again, as the
27
27
  newest version. It waits for a person to make it current, as a push does.