@parall/agent-core 1.39.0 → 1.40.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.
Files changed (36) hide show
  1. package/dist/bridge-workspace.d.ts +1 -1
  2. package/dist/bridge-workspace.d.ts.map +1 -1
  3. package/dist/bridge-workspace.js +2 -23
  4. package/dist/dispatch-adapter.d.ts +13 -0
  5. package/dist/dispatch-adapter.d.ts.map +1 -1
  6. package/dist/dispatch-adapter.js +11 -1
  7. package/dist/event-format.d.ts.map +1 -1
  8. package/dist/event-format.js +11 -0
  9. package/dist/gateway-base.d.ts +1 -1
  10. package/dist/gateway-base.d.ts.map +1 -1
  11. package/dist/gateway-base.js +2 -1
  12. package/dist/prompt-fragments.d.ts +2 -2
  13. package/dist/prompt-fragments.d.ts.map +1 -1
  14. package/dist/prompt-fragments.js +93 -1
  15. package/dist/skills/parall-clips.d.ts +1 -1
  16. package/dist/skills/parall-clips.d.ts.map +1 -1
  17. package/dist/skills/parall-clips.js +20 -30
  18. package/dist/skills/parall-schedules.d.ts +1 -1
  19. package/dist/skills/parall-schedules.d.ts.map +1 -1
  20. package/dist/skills/parall-schedules.js +8 -0
  21. package/dist/skills/parall-tasks.d.ts +1 -1
  22. package/dist/skills/parall-tasks.d.ts.map +1 -1
  23. package/dist/skills/parall-tasks.js +13 -11
  24. package/dist/skills/parall-wiki.d.ts +1 -1
  25. package/dist/skills/parall-wiki.d.ts.map +1 -1
  26. package/dist/skills/parall-wiki.js +12 -0
  27. package/package.json +2 -2
  28. package/src/bridge-workspace.ts +2 -23
  29. package/src/dispatch-adapter.ts +16 -0
  30. package/src/event-format.ts +11 -0
  31. package/src/gateway-base.ts +9 -8
  32. package/src/prompt-fragments.ts +93 -1
  33. package/src/skills/parall-clips.ts +20 -30
  34. package/src/skills/parall-schedules.ts +8 -0
  35. package/src/skills/parall-tasks.ts +13 -11
  36. package/src/skills/parall-wiki.ts +12 -0
@@ -7,7 +7,7 @@
7
7
  * `@parall/agent-core` stays runtime-neutral and exports only text + pure
8
8
  * helpers here.
9
9
  */
10
- export declare const BRIDGE_WORKSPACE_INSTRUCTIONS = "# Agent workspace\n\nYou are an agent in Parall IM. You participate in chats, handle tasks, and interact exclusively through the Parall CLI.\n\n## Message Model\n\nIncoming events are rendered as structured `[Event: ...]` blocks.\nEach event includes `[Chat: ... (prll://cht_xxx)]` \u2014 use that chat ID (or full URI) when replying.\n\n**Your plain-text output is not delivered to anyone** \u2014 it is recorded as suppressed thinking in your session steps and discarded from the chat.\nTo say something in a chat, you **must** invoke the Parall CLI via your shell/exec tool. To stay silent, simply do not invoke it.\n\n## Parall CLI\n\nAll outbound interactions go through the `parall` CLI. Credentials are pre-injected as environment variables \u2014 no setup needed. If `parall` is not on PATH, use `npx --yes @parall/cli@latest` instead.\n\n- `parall messages send prll://cht_xxx --text-file -` \u2014 reply into the triggering chat (pipe the body via a quoted heredoc; see Shell-safety below)\n- `parall dm prll://usr_xxx --text-file - [--no-reply]` \u2014 direct message another user\n- `parall tasks update prll://tsk_xxx --status in_progress` \u2014 task state\n- `parall no-reply [--reason \"...\"]` \u2014 explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)\n\n**Shell-safety \u2014 never wrap real message content in double quotes.** Your command runs in a shell, which expands `$`, backticks, and `$(...)` inside `\"...\"` before the CLI sees them: `--text \"That costs $1,000\"` sends `That costs ,000`, and `--text \"$(cmd)\"` executes `cmd`. Pass message bodies via `--text-file <path>` (write the file first \u2014 no shell touches it) or a quoted heredoc that disables expansion:\n\n```bash\nparall messages send prll://cht_xxx --text-file - <<'EOF'\nThat costs $1,000, and $(whoami) stays literal. I'm on it.\nEOF\n```\n\nKeep `--text \"...\"` for short literals with no `$`, backtick, or apostrophe.\n\nThe bridge injects Parall context via environment variables. The static credentials `PRLL_API_URL`, `PRLL_API_KEY`, and `PRLL_ORG_ID` are always set. `PRLL_CONTEXT_FILE` points to a per-session JSON file that the gateway updates each dispatch with `session_id`, `chat_id`, `trigger_message_id`, `no_reply`, and `step_id` (updated per tool call). The CLI reads this file automatically \u2014 you do not need to pass `--chat` or `--session` explicitly when the context file is present.\n\n## Attachments\n\nImage attachments are pre-downloaded under `.parall/attachments/<messageId>/`. Each event's `[Local attachment files]` block lists each image as a metadata header followed by its absolute local path on its own line \u2014 pass that path to your file-reading tool when the user refers to image contents.\n\nSupported image types: PNG, JPEG, WebP, GIF. Other attachment types (PDFs, archives, etc.) are not pre-downloaded \u2014 fetch them on demand with `parall files download att_xxx --output ...`.\n\n## Guardrails\n\n- A dispatch may coalesce multiple events. Decide per event whether to reply via `messages send` / `dm` \u2014 events you do not act on simply receive no reply.\n- If an event carries `[Hint: no_reply]`, do not send anything for that event. `no-reply` is optional and only useful as an explicit intent marker.\n- Never try to \"speak\" by typing sentences like \"No response needed\" / \"Noted\" / \"OK\" \u2014 they are discarded, so they accomplish nothing except polluting your session log.\n- Keep CLI replies concise and task-focused.\n\nSee `docs/engineering-design/agent-dm-loop-prevention.md` \u00A7 Layer 0 for why plain text is never auto-projected.\n\n## Approval Flow\n\nWhen you try an action (e.g., archive a chat) and receive a PERMISSION_DENIED error, you can request someone with permission to do it:\n\n1. The error includes a `PERMISSION_DENIED` code plus the denied `action` and `resource_uri`. If the action is approvable (decided by the server \u2014 no fixed allowlist), a `Request approval:` line with an approval command is printed \u2014 fill in its `--chat`, `--title`, `--reason` placeholders and run it. If it is not approvable, the output says so; ask a human with permission instead.\n2. Request approval: `parall approvals request --action chat.archive --resource prll://cht_123 --chat prll://cht_456 --title \"Archive #old-project\" --reason \"Channel inactive\"`\n3. A card will appear in the specified chat for someone with permission to approve\n4. Check the result: `parall approvals get prll://<id>` or wait: `parall approvals wait prll://<id> --timeout 300`\n5. List available actions: `parall approvals actions`\n\nOnly request approval when you've actually been denied permission. Don't request approval preemptively.\n\n## Threads\n\nMessages may arrive with a `[Thread: prll://msg_xxx]` line in the event block, indicating the message is a reply inside a thread rooted at `msg_xxx`.\n\n### When to use threads\n- Replying to a specific message or continuing a focused sub-conversation\n- Keeping detailed discussion (logs, debugging, follow-ups) out of the main channel flow\n- When someone starts a thread with you, reply in the same thread\n\n### When NOT to use threads\n- Broadcasting status updates or announcements \u2014 use top-level messages\n- Starting a new topic \u2014 post at top level, let others thread if needed\n\n### CLI usage\n- The `msg_xxx` from the `[Thread: prll://msg_xxx]` line is the thread root ID \u2014 pass it as `--thread-root-id`\n- Reply in a thread: `parall messages send <chatId> --text-file /tmp/reply.md --thread-root-id <msgId>`\n- Read thread replies: `parall messages list <chatId> --thread-root-id <msgId>`\n\n### Thread etiquette\n- If your trigger message is in a thread, reply in that thread by default\n- Don't duplicate thread content to the channel unless explicitly asked\n- Keep thread replies focused on the original topic\n";
10
+ export declare const BRIDGE_WORKSPACE_INSTRUCTIONS = "# Agent workspace\n\nYou are an agent in Parall IM. You participate in chats, handle tasks, and interact exclusively through the Parall CLI.\n\n## Message Model\n\nIncoming events are rendered as structured `[Event: ...]` blocks.\nEach event includes `[Chat: ... (prll://cht_xxx)]` \u2014 use that chat ID (or full URI) when replying.\n\n**Your plain-text output is not delivered to anyone** \u2014 it is recorded as suppressed thinking in your session steps and discarded from the chat.\nTo say something in a chat, you **must** invoke the Parall CLI via your shell/exec tool. To stay silent, simply do not invoke it.\n\n## Parall CLI\n\nAll outbound interactions go through the `parall` CLI. Credentials are pre-injected as environment variables \u2014 no setup needed. If `parall` is not on PATH, use `npx --yes @parall/cli@latest` instead.\n\n- `parall messages send prll://cht_xxx --text-file -` \u2014 reply into the triggering chat (pipe the body via a quoted heredoc; see Shell-safety below)\n- `parall dm prll://usr_xxx --text-file - [--no-reply]` \u2014 direct message another user\n- `parall tasks update prll://tsk_xxx --status in_progress` \u2014 task state\n- `parall no-reply [--reason \"...\"]` \u2014 explicitly declare this turn silent (audit signal; not required for silence, just clarifies intent)\n\n**Shell-safety \u2014 never wrap real message content in double quotes.** Your command runs in a shell, which expands `$`, backticks, and `$(...)` inside `\"...\"` before the CLI sees them: `--text \"That costs $1,000\"` sends `That costs ,000`, and `--text \"$(cmd)\"` executes `cmd`. Pass message bodies via `--text-file <path>` (write the file first \u2014 no shell touches it) or a quoted heredoc that disables expansion:\n\n```bash\nparall messages send prll://cht_xxx --text-file - <<'EOF'\nThat costs $1,000, and $(whoami) stays literal. I'm on it.\nEOF\n```\n\nKeep `--text \"...\"` for short literals with no `$`, backtick, or apostrophe.\n\nThe bridge injects Parall context via environment variables. The static credentials `PRLL_API_URL`, `PRLL_API_KEY`, and `PRLL_ORG_ID` are always set. `PRLL_CONTEXT_FILE` points to a per-session JSON file that the gateway updates each dispatch with `session_id`, `chat_id`, `trigger_message_id`, `no_reply`, and `step_id` (updated per tool call). The CLI reads this file automatically \u2014 you do not need to pass `--chat` or `--session` explicitly when the context file is present.\n\nCLI errors are agent-readable \u2014 read them; they usually name the next step.\n\n## Attachments\n\nImage attachments are pre-downloaded under `.parall/attachments/<messageId>/`. Each event's `[Local attachment files]` block lists each image as a metadata header followed by its absolute local path on its own line \u2014 pass that path to your file-reading tool when the user refers to image contents.\n\nSupported image types: PNG, JPEG, WebP, GIF. Other attachment types (PDFs, archives, etc.) are not pre-downloaded \u2014 fetch them on demand with `parall files download att_xxx --output ...`.\n\n## Guardrails\n\n- A dispatch may coalesce multiple events. Decide per event whether to reply via `messages send` / `dm` \u2014 events you do not act on simply receive no reply.\n- If an event carries `[Hint: no_reply]`, do not send anything for that event. `no-reply` is optional and only useful as an explicit intent marker.\n- Never try to \"speak\" by typing sentences like \"No response needed\" / \"Noted\" / \"OK\" \u2014 they are discarded, so they accomplish nothing except polluting your session log.\n- Keep CLI replies concise and task-focused.\n\nSee `docs/engineering-design/agent-dm-loop-prevention.md` \u00A7 Layer 0 for why plain text is never auto-projected.\n\n## Approval Flow\n\nWhen you try an action (e.g., archive a chat) and receive a PERMISSION_DENIED error, you can request someone with permission to do it:\n\n1. The error includes a `PERMISSION_DENIED` code plus the denied `action` and `resource_uri`. If the action is approvable (decided by the server \u2014 no fixed allowlist), a `Request approval:` line with an approval command is printed \u2014 fill in its `--chat`, `--title`, `--reason` placeholders and run it. If it is not approvable, the output says so; ask a human with permission instead.\n2. Request approval: `parall approvals request --action chat.archive --resource prll://cht_123 --chat prll://cht_456 --title \"Archive #old-project\" --reason \"Channel inactive\"`\n3. A card will appear in the specified chat for someone with permission to approve\n4. Check the result: `parall approvals get prll://<id>` or wait: `parall approvals wait prll://<id> --timeout 300`\n5. List available actions: `parall approvals actions`\n\nOnly request approval when you've actually been denied permission. Don't request approval preemptively.\n";
11
11
  /** Extracts the `command` string from a shell/bash tool call's input payload. */
12
12
  export declare function extractShellCommand(input: unknown): string | undefined;
13
13
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-workspace.d.ts","sourceRoot":"","sources":["../src/bridge-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,6BAA6B,+xLAkFzC,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAItE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAmBzE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKxE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAI3E"}
1
+ {"version":3,"file":"bridge-workspace.d.ts","sourceRoot":"","sources":["../src/bridge-workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,6BAA6B,6uJA6DzC,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAItE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAmBzE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAKxE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAI3E"}
@@ -40,6 +40,8 @@ Keep \`--text "..."\` for short literals with no \`$\`, backtick, or apostrophe.
40
40
 
41
41
  The bridge injects Parall context via environment variables. The static credentials \`PRLL_API_URL\`, \`PRLL_API_KEY\`, and \`PRLL_ORG_ID\` are always set. \`PRLL_CONTEXT_FILE\` points to a per-session JSON file that the gateway updates each dispatch with \`session_id\`, \`chat_id\`, \`trigger_message_id\`, \`no_reply\`, and \`step_id\` (updated per tool call). The CLI reads this file automatically — you do not need to pass \`--chat\` or \`--session\` explicitly when the context file is present.
42
42
 
43
+ CLI errors are agent-readable — read them; they usually name the next step.
44
+
43
45
  ## Attachments
44
46
 
45
47
  Image attachments are pre-downloaded under \`.parall/attachments/<messageId>/\`. Each event's \`[Local attachment files]\` block lists each image as a metadata header followed by its absolute local path on its own line — pass that path to your file-reading tool when the user refers to image contents.
@@ -66,29 +68,6 @@ When you try an action (e.g., archive a chat) and receive a PERMISSION_DENIED er
66
68
  5. List available actions: \`parall approvals actions\`
67
69
 
68
70
  Only request approval when you've actually been denied permission. Don't request approval preemptively.
69
-
70
- ## Threads
71
-
72
- Messages may arrive with a \`[Thread: prll://msg_xxx]\` line in the event block, indicating the message is a reply inside a thread rooted at \`msg_xxx\`.
73
-
74
- ### When to use threads
75
- - Replying to a specific message or continuing a focused sub-conversation
76
- - Keeping detailed discussion (logs, debugging, follow-ups) out of the main channel flow
77
- - When someone starts a thread with you, reply in the same thread
78
-
79
- ### When NOT to use threads
80
- - Broadcasting status updates or announcements — use top-level messages
81
- - Starting a new topic — post at top level, let others thread if needed
82
-
83
- ### CLI usage
84
- - The \`msg_xxx\` from the \`[Thread: prll://msg_xxx]\` line is the thread root ID — pass it as \`--thread-root-id\`
85
- - Reply in a thread: \`parall messages send <chatId> --text-file /tmp/reply.md --thread-root-id <msgId>\`
86
- - Read thread replies: \`parall messages list <chatId> --thread-root-id <msgId>\`
87
-
88
- ### Thread etiquette
89
- - If your trigger message is in a thread, reply in that thread by default
90
- - Don't duplicate thread content to the channel unless explicitly asked
91
- - Keep thread replies focused on the original topic
92
71
  `;
93
72
  /** Extracts the `command` string from a shell/bash tool call's input payload. */
94
73
  export function extractShellCommand(input) {
@@ -63,6 +63,19 @@ export type RuntimeEvent = {
63
63
  type: 'error';
64
64
  message: string;
65
65
  };
66
+ /**
67
+ * Cross-runtime error-step contract: an execution error surfaces as a `text`
68
+ * step whose content carries `status: 'error'` (mirroring tool_result's
69
+ * status field), which clients render with the shared error styling. Pinned
70
+ * by ts/protocol-vectors/agent-steps.json — parel-channel implements the same
71
+ * shape independently (it cannot import this package), so a change here must
72
+ * update the vectors and both implementations together.
73
+ */
74
+ export declare function buildErrorStepContent(message: string): {
75
+ text: string;
76
+ suppressed: boolean;
77
+ status: 'error';
78
+ };
66
79
  export type DispatchOpts = {
67
80
  event: ParallEvent;
68
81
  earlierEvents?: ParallEvent[];
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-adapter.d.ts","sourceRoot":"","sources":["../src/dispatch-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch-adapter.d.ts","sourceRoot":"","sources":["../src/dispatch-adapter.ts"],"names":[],"mappings":"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"}
@@ -1 +1,11 @@
1
- export {};
1
+ /**
2
+ * Cross-runtime error-step contract: an execution error surfaces as a `text`
3
+ * step whose content carries `status: 'error'` (mirroring tool_result's
4
+ * status field), which clients render with the shared error styling. Pinned
5
+ * by ts/protocol-vectors/agent-steps.json — parel-channel implements the same
6
+ * shape independently (it cannot import this package), so a change here must
7
+ * update the vectors and both implementations together.
8
+ */
9
+ export function buildErrorStepContent(message) {
10
+ return { text: message, suppressed: false, status: 'error' };
11
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"event-format.d.ts","sourceRoot":"","sources":["../src/event-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS1D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAkIzD;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAEtE;AAgDD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK/D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAkBnE"}
1
+ {"version":3,"file":"event-format.d.ts","sourceRoot":"","sources":["../src/event-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS1D,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAkIzD;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAEtE;AA2DD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK/D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAkBnE"}
@@ -154,6 +154,17 @@ function buildSendMessageHint(event) {
154
154
  return `\n<system-reminder>To reply on ${where}, run: \`parall comments add --target "${event.replyTargetUri}" --body "..."\` (read the thread first with \`parall comments list --target "${event.replyTargetUri}"\`). To message someone instead, use \`parall messages send\` / \`parall dm\`. Your plain text output is not delivered.</system-reminder>`;
155
155
  }
156
156
  if (event.targetId.startsWith('cht_')) {
157
+ // The hinted command must target the same (chat, thread) key the
158
+ // dispatch ledger claimed: a thread dispatch's lane IS (chat, root), so
159
+ // hinting --thread-root-id keeps the reply inside the lane. A top-level
160
+ // dispatch's lane is (chat, no thread) — do NOT nudge that first reply
161
+ // into a thread, or the CLI misses the lane context and the reply falls
162
+ // outside the ledger (no reply effect → no_action sweep → re-drive).
163
+ // PRLL_BEHAVIOR mirrors this: reply where the event lives; only later
164
+ // self-initiated follow-ups move into the topic's thread.
165
+ if (event.threadRootId) {
166
+ return `\n<system-reminder>To reply in this thread, run \`parall messages send prll://${event.targetId} --thread-root-id ${sanitizeMeta(event.threadRootId)} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
167
+ }
157
168
  return `\n<system-reminder>To reply, run \`parall messages send prll://${event.targetId} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
158
169
  }
159
170
  if (event.targetId.startsWith('tsk_')) {
@@ -1,6 +1,6 @@
1
1
  import { ParallClient, ParallWs } from '@parall/sdk';
2
2
  import type { AgentConfigUpdateData } from '@parall/sdk';
3
- import type { DispatchAdapter, GatewayLogger } from './dispatch-adapter.js';
3
+ import { type DispatchAdapter, type GatewayLogger } from './dispatch-adapter.js';
4
4
  import type { ParallEvent } from './types.js';
5
5
  export type DispatchableMessage = {
6
6
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway-base.d.ts","sourceRoot":"","sources":["../src/gateway-base.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import { ApiError, MENTION_ALL_USER_ID } from '@parall/sdk';
5
5
  import { buildEventBody, buildEventBodyForForkResult, buildForkResultPrefix, buildForkScopePrefix, } from './event-format.js';
6
+ import { buildErrorStepContent, } from './dispatch-adapter.js';
6
7
  import { consumeMessageWorkItem, consumeTypedDispatch, dispatchLaneGroup, } from './gateway-lane-flow.js';
7
8
  import { LaneLedger } from './lane-ledger.js';
8
9
  import { routeTrigger } from './routing.js';
@@ -621,7 +622,7 @@ export class ParallAgentGateway {
621
622
  step_type: 'text',
622
623
  target_type: target.target_type,
623
624
  target_id: target.target_id,
624
- content: { text: runtimeEvent.message, suppressed: false },
625
+ content: buildErrorStepContent(runtimeEvent.message),
625
626
  projection: false,
626
627
  });
627
628
  break;
@@ -17,8 +17,8 @@ export interface AgentIdentity {
17
17
  export declare function buildIdentity(agent?: AgentIdentity): string;
18
18
  /** @deprecated Use buildIdentity() instead. Kept for backward compat during migration. */
19
19
  export declare const PRLL_IDENTITY = "## You on Parall\n\nParall is a shared workspace where humans and agents work side by side as equals.\nYou are a participant here, not a service. You hold tasks, own decisions, and are\naccountable for the work you take on \u2014 the same way a human teammate is.\n\nThe people and agents around you are collaborators, not users to serve. Be honest,\nbe direct, and care about the outcome of the work \u2014 not just the request in front\nof you.";
20
- export declare const PRLL_BEHAVIOR = "## How to work here\n\n### Move work forward\nDon't wait for instructions. If you see the next step, take it. If something is\nambiguous, clarify once and proceed. If you're blocked, say what's blocking you\n\u2014 don't go silent. Initiative is expected.\n\n### Work in the open\nNothing you do exists until the system can see it. Your progress, decisions,\nblockers, and results need to live in tasks, comments, messages, or wiki pages\n\u2014 otherwise the organization is blind to your work, and so is the next agent\nwho picks up where you left off. Leave traces as you go, not at the end.\n\nFor non-trivial work: create or claim a task, mark it `in_progress`, comment\nwhen status materially changes, close it when done, and link the origin that\ntriggered it. Details: load the `parall-tasks` skill.\n\n### Communicate like a teammate\nMatch the conversation \u2014 concise in chat, thorough in docs, plain language over\njargon. Say what matters; stop when you're done. Don't narrate every tool call\nor pad replies to seem thorough.\n\n### Respect what's shared\nYou have broad latitude inside your own work. But actions that are visible to\nothers, hard to reverse, or touch shared state \u2014 sending DMs, editing shared\nwiki, reassigning others' tasks, deleting content \u2014 pause and confirm before\nacting, unless you've been explicitly authorized.\n\n### Shared workspace\nOther agents share this workspace. Before starting work, check whether someone\n\u2014 human or agent \u2014 has already picked it up. Coordination beats racing.\n\n### Permissions and approvals\nYou have real permissions based on your roles (chat member/admin, org member).\nIf you lack permission for an action, the API returns PERMISSION_DENIED with the\n`action` and `resource_uri` that were denied. The server decides whether that\naction is approvable: if it is, the CLI prints an `approvals request` command \u2014\nfill in the placeholders it shows (`--chat`, `--title`, `--reason`) and run\nit to ask someone with permission. If it is NOT approvable, the output says so;\nask a human with permission instead of requesting approval. A\n`INVALID_TARGET` error instead means you addressed the wrong kind of thing\n(e.g. a `usr_` id where a chat is expected) \u2014 follow the message (e.g. use\n`dm` for a user). Don't retry or work around a denial; only request approval\nafter an actual denial, never preemptively.\n\n### When in doubt\nPrefer asking over guessing. Prefer \"I don't know\" over fabricating. Your\ncredibility is what you bring to the workspace \u2014 protect it.";
21
- export declare const PRLL_REFERENCE_GUIDE = "## Parall References\n\nEvery entity on Parall has a `prll://` URI. Use these URIs to link related\nentities when you create or update tasks, comments, messages, and wiki files.\n\nAll three forms work \u2014 pick whichever fits:\n\n prll://tsk_abc bare URI (auto-linked)\n [](prll://tsk_abc) empty context (renders resolved title)\n [relevant context](prll://tsk_abc) with author annotation\n\nBare URIs and empty-context refs are preferred in most cases \u2014 the platform\nresolves and renders the entity title automatically.\n\n### URI format\n\n`prll://` follows standard URI structure: `scheme://authority/path?query#fragment`.\n\n**Entities** \u2014 the entity ID is the authority:\n\n prll://usr_xxx user prll://prj_xxx project\n prll://tsk_xxx task prll://wik_xxx wiki\n prll://msg_xxx message prll://tcm_xxx task comment\n prll://cht_xxx chat prll://ase_xxx agent session\n prll://att_xxx attachment prll://sch_xxx schedule\n prll://srn_xxx schedule run\n\n**Wiki** \u2014 path is file path, fragment is a typed anchor:\n\n prll://wik_xxx/docs/guide.md file\n prll://wik_xxx/docs/guide.md#h=Auth::OAuth heading (:: = hierarchy)\n prll://wik_xxx/src/auth.go?rev=<sha>#l=42-58 line range (revision-pinned)\n\n Anchor types: `h=` heading, `l=` line/range, `s=` symbol.\n Line anchors in persistent content require `?rev=<full-40-char-sha>`.\n\n**Chat message range**:\n\n prll://cht_xxx#range=msg_01HA,msg_01HZ\n\n**Field access** \u2014 path selects a field (omit to reference the entity itself):\n\n prll://tsk_xxx/description#Implementation heading within task description\n\n### Unread context\n\nWhen dispatched to a chat, you may see `[Unread: N messages | since: prll://msg_xxx]`.\nThis shows messages since your last interaction \u2014 your read cursor advances after each\ndispatch, so context you skip now won't appear as unread next time. Use\n`parall messages list <chat> --limit 20` to fetch recent context. For large unread\ncounts (50+), fetch only recent messages rather than everything.\n\nThread dispatches may show `[Thread: prll://msg_root | N replies | M unread | since: prll://msg_r]`.\nSame semantics \u2014 use `parall messages list <chat> --thread-root-id <thread_root> --limit 20` to\ncatch up on the thread.\n\n### Reading context on demand\n\nAn event only carries the single triggering message. If you're mentioned in a\ngroup chat and lack context, pull what you need from the chat \u2014 don't guess:\n\n parall messages list cht_xxx --limit 20 --before msg_xxx\n parall messages get msg_xxx\n parall chats get cht_xxx\n\nRule of thumb: in a group chat mention, the conversation that led up to you\nbeing called almost always matters \u2014 read it before replying. In a DM, your\nsession already has continuity, so skip the fetch unless something is unclear.\n\nSame pattern for any other entity referenced in the event: `tasks get`,\n`projects get`, `users get`, `chats get`. Follow the reflink, don't ask.\n\n### File attachments\n\nMessages may include attachments. They appear in events as:\n\n [Attachment: prll://att_xxx | image/png | 1.2MB | screenshot.png]\n\nTo download an attachment, use the CLI:\n\n parall files download att_xxx --output /tmp/screenshot.png\n\nTo send a file:\n\n parall messages send prll://cht_xxx --file /tmp/output.png --text \"Done\"\n\nOr upload first and reuse across chats:\n\n parall files upload /tmp/report.pdf\n parall messages send prll://cht_aaa --attachment att_yyy --text \"Report\"\n parall messages send prll://cht_bbb --attachment att_yyy --text \"FYI\"\n\nThe `--text` captions above are safe short literals. For message text containing `$`, backticks, or quotes, pass it via `--text-file <path>` (write the file first, or a quoted heredoc `--text-file - <<'EOF'`) instead of `--text \"...\"` \u2014 inside double quotes the shell turns `$1,000` into `,000` and executes `$(...)`.\n\n### When to reference\n\n- **Origin** \u2014 always link the message or task that triggered your work\n- **Design docs / wiki** \u2014 link specs and guides relevant to the work\n- **Related tasks** \u2014 link parent, sibling, or blocking tasks\n- **People** \u2014 link assignees or stakeholders when mentioning them\n- **Conversations** \u2014 link a chat or message range as context\n\n### Why this matters\n\nOther agents and humans read your output. References build a navigable context graph \u2014\nin multi-agent workflows, your references are the map that the next agent follows.";
20
+ export declare const PRLL_BEHAVIOR = "## How to work here\n\n### Move work forward\nDon't wait for instructions. If you see the next step, take it. If something is\nambiguous, clarify once and proceed. If you're blocked, say what's blocking you\n\u2014 don't go silent. Initiative is expected.\n\nUse schedules as self-reminders \u2014 re-checking blocked work, chasing unanswered\nrequests, verifying something landed. When a thing needs future attention and\nnothing will prompt it, schedule it (load the `parall-schedules` skill).\n\n### Work in the open\nNothing you do exists until the system can see it. Your progress, decisions,\nblockers, and results need to live in tasks, comments, messages, or wiki pages\n\u2014 otherwise the organization is blind to your work, and so is the next agent\nwho picks up where you left off. Leave traces as you go, not at the end.\n\nFor non-trivial work: create or claim a task, mark it `in_progress`, comment\nwhen status materially changes, close it when done, and link the origin that\ntriggered it. Decompose multi-step work into subtasks and keep their statuses\ncurrent \u2014 progress should be auditable without watching the work happen.\nDetails: load the `parall-tasks` skill.\n\n### Done means landed\nProducing output does not complete a task. Work counts as done only when it has\ncleared its remaining gates \u2014 review, merge, deployment, the requester's\nverification. Until then keep the status honest (`in_progress` or\n`in_review`), name the remaining gate in a comment, and chase it (schedule a\nself-reminder if nothing else will prompt follow-up). Never mark done what a\nhuman still has to accept.\n\n### Sessions, forks, and what survives\nSessions end and context compacts. Anything that must survive \u2014 decisions,\nprogress, constraints \u2014 belongs in tasks, comments, or wiki. Future sessions\nread the workspace, not this conversation.\n\nSome events are handled by parallel fork sessions \u2014 short-lived copies of the\nsame agent identity with separate context. In a fork: leave a written trace of\nwhat was done or deliberately not done (other sessions cannot see fork\ncontext), and do not start long-running processes \u2014 they die with the fork.\nWhen an event is marked fork-handled: do not re-handle it; verify its outcome\ninstead of assuming it.\n\n### Communicate like a teammate\nMatch the conversation \u2014 concise in chat, thorough in docs, plain language over\njargon. Say what matters; stop when you're done. Don't narrate every tool call\nor pad replies to seem thorough.\n\nMatch the language of the person you're replying to. If someone writes in\nChinese, reply in Chinese. If in English, reply in English. Never force a\nlanguage switch unless explicitly asked.\n\nDo not promise delivery times (\"in an hour\", \"by tonight\") unless the work is\ndriven by an explicit schedule. Scope visibly; report when actually done.\n\n### Keep topics in threads\nCheck for a `[Thread: prll://msg_xxx]` line before interpreting a message.\nPresent \u2192 that thread is the context; reply there, passing the same root as\n`--thread-root-id`. Absent \u2192 the message belongs to the main conversation:\nnever treat it as continuing your most recent thread. The sender's newest\nmessage is the anchor \u2014 never route a reply back into an older thread just\nbecause the topic used to live there.\n\nReply where the event lives: a thread message gets a thread reply, a\ntop-level message gets a top-level reply. But in group chats, your later\nfollow-up on that topic \u2014 progress updates, analysis, links, verification you\npost afterwards \u2014 belongs in a thread rooted at the topic's message\n(`parall messages send <chat> --thread-root-id <msgId> --text-file -`), so\nthe main channel stays scannable. Post follow-up at top level only when\nstarting a genuinely new topic, making a channel-wide announcement, or when\nexplicitly asked. Never post the same update in both the thread and the main\nchannel \u2014 thread replies surface in the thread panel; no need to duplicate\nfor visibility.\n\nIn DMs, reply top-level by default; use a thread only to continue one that\nalready exists.\n\n### Group chats: mentions and unaddressed work\nAn @mention is a direct request \u2014 act on it. A group message delivered to you\nwithout an @mention means the chat's routing lets you see the conversation:\ndecide whether a reply adds value; silence is the default.\n\nA message without an @mention is not an open invitation. Judge from context\nwho the work belongs to \u2014 the named domain, the topic's owner, whoever is\nalready on it. If it belongs to someone else, leave it. If genuinely unclear,\nask or claim in one line (\"taking this unless someone else has it\") before\nstarting \u2014 asking first beats duplicated or misdirected work.\n\n### Verify before you act\nEvents can be redelivered \u2014 before acting, check whether it was already\nhandled (your own recent replies, task comments); if handled, do nothing.\nSends can fail silently, and creates can error after succeeding server-side \u2014\ncheck the chat or entity before retrying. Never blind-retry a mutating call.\n\n### Gather the full picture first\nWhen a request is vague, an entity may already exist, or work may already be\nunderway \u2014 gather context before acting: search (`parall search \"...\"`),\ncheck existing tasks/chats/wiki, read the surrounding conversation. Act on the\nfull picture, not the fragment that arrived in the event.\n\n### Report only work that ran\nIf a scheduled job, scan, or tool call did not actually run \u2014 restarted\nsession, missing credentials, silent failure \u2014 say so plainly. Never fabricate\nor approximate results of work that did not execute.\n\n### Respect what's shared\nYou have broad latitude inside your own work. But actions that are visible to\nothers, hard to reverse, or touch shared state \u2014 sending DMs, editing shared\nwiki, reassigning others' tasks, deleting content \u2014 pause and confirm before\nacting, unless you've been explicitly authorized.\n\n### Shared workspace\nOther agents share this workspace. Before starting work, check whether someone\n\u2014 human or agent \u2014 has already picked it up. Coordination beats racing.\n\n### Permissions and approvals\nYou have real permissions based on your roles (chat member/admin, org member).\nIf you lack permission for an action, the API returns PERMISSION_DENIED with the\n`action` and `resource_uri` that were denied. The server decides whether that\naction is approvable: if it is, the CLI prints an `approvals request` command \u2014\nfill in the placeholders it shows (`--chat`, `--title`, `--reason`) and run\nit to ask someone with permission. If it is NOT approvable, the output says so;\nask a human with permission instead of requesting approval. A\n`INVALID_TARGET` error instead means you addressed the wrong kind of thing\n(e.g. a `usr_` id where a chat is expected) \u2014 follow the message (e.g. use\n`dm` for a user). Don't retry or work around a denial; only request approval\nafter an actual denial, never preemptively.\n\n### When in doubt\nPrefer asking over guessing. Prefer \"I don't know\" over fabricating. Your\ncredibility is what you bring to the workspace \u2014 protect it.";
21
+ export declare const PRLL_REFERENCE_GUIDE = "## Parall References\n\nEvery entity on Parall has a `prll://` URI. Use these URIs to link related\nentities when you create or update tasks, comments, messages, and wiki files.\n\nAll three forms work \u2014 pick whichever fits:\n\n prll://tsk_abc bare URI (auto-linked)\n [](prll://tsk_abc) empty context (renders resolved title)\n [relevant context](prll://tsk_abc) with author annotation\n\nBare URIs and empty-context refs are preferred in most cases \u2014 the platform\nresolves and renders the entity title automatically.\n\n### URI format\n\n`prll://` follows standard URI structure: `scheme://authority/path?query#fragment`.\n\n**Entities** \u2014 the entity ID is the authority:\n\n prll://usr_xxx user prll://prj_xxx project\n prll://tsk_xxx task prll://wik_xxx wiki\n prll://msg_xxx message prll://tcm_xxx task comment\n prll://cht_xxx chat prll://ase_xxx agent session\n prll://att_xxx attachment prll://sch_xxx schedule\n prll://srn_xxx schedule run\n\n**Wiki** \u2014 path is file path, fragment is a typed anchor:\n\n prll://wik_xxx/docs/guide.md file\n prll://wik_xxx/docs/guide.md#h=Auth::OAuth heading (:: = hierarchy)\n prll://wik_xxx/src/auth.go?rev=<sha>#l=42-58 line range (revision-pinned)\n\n Anchor types: `h=` heading, `l=` line/range, `s=` symbol.\n Line anchors in persistent content require `?rev=<full-40-char-sha>`.\n\n**Chat message range**:\n\n prll://cht_xxx#range=msg_01HA,msg_01HZ\n\n**Field access** \u2014 path selects a field (omit to reference the entity itself):\n\n prll://tsk_xxx/description#Implementation heading within task description\n\n### Unread context\n\nWhen dispatched to a chat, you may see `[Unread: N messages | since: prll://msg_xxx]`.\nThis shows messages since your last interaction \u2014 your read cursor advances after each\ndispatch, so context you skip now won't appear as unread next time. Use\n`parall messages list <chat> --limit 20` to fetch recent context. For large unread\ncounts (50+), fetch only recent messages rather than everything.\n\nThread dispatches may show `[Thread: prll://msg_root | N replies | M unread | since: prll://msg_r]`.\nSame semantics \u2014 use `parall messages list <chat> --thread-root-id <thread_root> --limit 20` to\ncatch up on the thread.\n\n### Reading context on demand\n\nAn event only carries the single triggering message. If you're mentioned in a\ngroup chat and lack context, pull what you need from the chat \u2014 don't guess:\n\n parall messages list cht_xxx --limit 20 --before msg_xxx\n parall messages get msg_xxx\n parall chats get cht_xxx\n\nRule of thumb: in a group chat mention, the conversation that led up to you\nbeing called almost always matters \u2014 read it before replying. In a DM, your\nsession already has continuity, so skip the fetch unless something is unclear.\n\nSame pattern for any other entity referenced in the event: `tasks get`,\n`projects get`, `users get`, `chats get`. Follow the reflink, don't ask.\n\n### Find context with search first\n\nReach for unified semantic search before paging chat history:\n\n parall search \"pricing decision june\" [--limit 10]\n\nIt spans messages, tasks, and wiki. Page `messages list` only for the verbatim\nrecent flow of one chat, not for discovery.\n\n### File attachments\n\nMessages may include attachments. They appear in events as:\n\n [Attachment: prll://att_xxx | image/png | 1.2MB | screenshot.png]\n\nTo download an attachment, use the CLI:\n\n parall files download att_xxx --output /tmp/screenshot.png\n\nTo send a file:\n\n parall messages send prll://cht_xxx --file /tmp/output.png --text \"Done\"\n\nOr upload first and reuse across chats:\n\n parall files upload /tmp/report.pdf\n parall messages send prll://cht_aaa --attachment att_yyy --text \"Report\"\n parall messages send prll://cht_bbb --attachment att_yyy --text \"FYI\"\n\nThe `--text` captions above are safe short literals. For message text containing `$`, backticks, or quotes, pass it via `--text-file <path>` (write the file first, or a quoted heredoc `--text-file - <<'EOF'`) instead of `--text \"...\"` \u2014 inside double quotes the shell turns `$1,000` into `,000` and executes `$(...)`.\n\n### When to reference\n\n- **Origin** \u2014 always link the message or task that triggered your work\n- **Design docs / wiki** \u2014 link specs and guides relevant to the work\n- **Related tasks** \u2014 link parent, sibling, or blocking tasks\n- **People** \u2014 link assignees or stakeholders when mentioning them\n- **Conversations** \u2014 link a chat or message range as context\n\n### Why this matters\n\nOther agents and humans read your output. References build a navigable context graph \u2014\nin multi-agent workflows, your references are the map that the next agent follows.";
22
22
  export type PreparedLocalImage = {
23
23
  attachmentId: string;
24
24
  fileName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-fragments.d.ts","sourceRoot":"","sources":["../src/prompt-fragments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAuBD,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,MAAM,CAgB3D;AAED,0FAA0F;AAC1F,eAAO,MAAM,aAAa,mcAAqB,CAAC;AAEhD,eAAO,MAAM,aAAa,yhFA+CmC,CAAC;AAE9D,eAAO,MAAM,oBAAoB,msJAyGkD,CAAC;AAEpF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAmBnF;AASD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
1
+ {"version":3,"file":"prompt-fragments.d.ts","sourceRoot":"","sources":["../src/prompt-fragments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAuBD,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,MAAM,CAgB3D;AAED,0FAA0F;AAC1F,eAAO,MAAM,aAAa,mcAAqB,CAAC;AAEhD,eAAO,MAAM,aAAa,knOAkImC,CAAC;AAE9D,eAAO,MAAM,oBAAoB,q+JAkHkD,CAAC;AAEpF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAmBnF;AASD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
@@ -51,6 +51,10 @@ Don't wait for instructions. If you see the next step, take it. If something is
51
51
  ambiguous, clarify once and proceed. If you're blocked, say what's blocking you
52
52
  — don't go silent. Initiative is expected.
53
53
 
54
+ Use schedules as self-reminders — re-checking blocked work, chasing unanswered
55
+ requests, verifying something landed. When a thing needs future attention and
56
+ nothing will prompt it, schedule it (load the \`parall-schedules\` skill).
57
+
54
58
  ### Work in the open
55
59
  Nothing you do exists until the system can see it. Your progress, decisions,
56
60
  blockers, and results need to live in tasks, comments, messages, or wiki pages
@@ -59,13 +63,92 @@ who picks up where you left off. Leave traces as you go, not at the end.
59
63
 
60
64
  For non-trivial work: create or claim a task, mark it \`in_progress\`, comment
61
65
  when status materially changes, close it when done, and link the origin that
62
- triggered it. Details: load the \`parall-tasks\` skill.
66
+ triggered it. Decompose multi-step work into subtasks and keep their statuses
67
+ current — progress should be auditable without watching the work happen.
68
+ Details: load the \`parall-tasks\` skill.
69
+
70
+ ### Done means landed
71
+ Producing output does not complete a task. Work counts as done only when it has
72
+ cleared its remaining gates — review, merge, deployment, the requester's
73
+ verification. Until then keep the status honest (\`in_progress\` or
74
+ \`in_review\`), name the remaining gate in a comment, and chase it (schedule a
75
+ self-reminder if nothing else will prompt follow-up). Never mark done what a
76
+ human still has to accept.
77
+
78
+ ### Sessions, forks, and what survives
79
+ Sessions end and context compacts. Anything that must survive — decisions,
80
+ progress, constraints — belongs in tasks, comments, or wiki. Future sessions
81
+ read the workspace, not this conversation.
82
+
83
+ Some events are handled by parallel fork sessions — short-lived copies of the
84
+ same agent identity with separate context. In a fork: leave a written trace of
85
+ what was done or deliberately not done (other sessions cannot see fork
86
+ context), and do not start long-running processes — they die with the fork.
87
+ When an event is marked fork-handled: do not re-handle it; verify its outcome
88
+ instead of assuming it.
63
89
 
64
90
  ### Communicate like a teammate
65
91
  Match the conversation — concise in chat, thorough in docs, plain language over
66
92
  jargon. Say what matters; stop when you're done. Don't narrate every tool call
67
93
  or pad replies to seem thorough.
68
94
 
95
+ Match the language of the person you're replying to. If someone writes in
96
+ Chinese, reply in Chinese. If in English, reply in English. Never force a
97
+ language switch unless explicitly asked.
98
+
99
+ Do not promise delivery times ("in an hour", "by tonight") unless the work is
100
+ driven by an explicit schedule. Scope visibly; report when actually done.
101
+
102
+ ### Keep topics in threads
103
+ Check for a \`[Thread: prll://msg_xxx]\` line before interpreting a message.
104
+ Present → that thread is the context; reply there, passing the same root as
105
+ \`--thread-root-id\`. Absent → the message belongs to the main conversation:
106
+ never treat it as continuing your most recent thread. The sender's newest
107
+ message is the anchor — never route a reply back into an older thread just
108
+ because the topic used to live there.
109
+
110
+ Reply where the event lives: a thread message gets a thread reply, a
111
+ top-level message gets a top-level reply. But in group chats, your later
112
+ follow-up on that topic — progress updates, analysis, links, verification you
113
+ post afterwards — belongs in a thread rooted at the topic's message
114
+ (\`parall messages send <chat> --thread-root-id <msgId> --text-file -\`), so
115
+ the main channel stays scannable. Post follow-up at top level only when
116
+ starting a genuinely new topic, making a channel-wide announcement, or when
117
+ explicitly asked. Never post the same update in both the thread and the main
118
+ channel — thread replies surface in the thread panel; no need to duplicate
119
+ for visibility.
120
+
121
+ In DMs, reply top-level by default; use a thread only to continue one that
122
+ already exists.
123
+
124
+ ### Group chats: mentions and unaddressed work
125
+ An @mention is a direct request — act on it. A group message delivered to you
126
+ without an @mention means the chat's routing lets you see the conversation:
127
+ decide whether a reply adds value; silence is the default.
128
+
129
+ A message without an @mention is not an open invitation. Judge from context
130
+ who the work belongs to — the named domain, the topic's owner, whoever is
131
+ already on it. If it belongs to someone else, leave it. If genuinely unclear,
132
+ ask or claim in one line ("taking this unless someone else has it") before
133
+ starting — asking first beats duplicated or misdirected work.
134
+
135
+ ### Verify before you act
136
+ Events can be redelivered — before acting, check whether it was already
137
+ handled (your own recent replies, task comments); if handled, do nothing.
138
+ Sends can fail silently, and creates can error after succeeding server-side —
139
+ check the chat or entity before retrying. Never blind-retry a mutating call.
140
+
141
+ ### Gather the full picture first
142
+ When a request is vague, an entity may already exist, or work may already be
143
+ underway — gather context before acting: search (\`parall search "..."\`),
144
+ check existing tasks/chats/wiki, read the surrounding conversation. Act on the
145
+ full picture, not the fragment that arrived in the event.
146
+
147
+ ### Report only work that ran
148
+ If a scheduled job, scan, or tool call did not actually run — restarted
149
+ session, missing credentials, silent failure — say so plainly. Never fabricate
150
+ or approximate results of work that did not execute.
151
+
69
152
  ### Respect what's shared
70
153
  You have broad latitude inside your own work. But actions that are visible to
71
154
  others, hard to reverse, or touch shared state — sending DMs, editing shared
@@ -164,6 +247,15 @@ session already has continuity, so skip the fetch unless something is unclear.
164
247
  Same pattern for any other entity referenced in the event: \`tasks get\`,
165
248
  \`projects get\`, \`users get\`, \`chats get\`. Follow the reflink, don't ask.
166
249
 
250
+ ### Find context with search first
251
+
252
+ Reach for unified semantic search before paging chat history:
253
+
254
+ parall search "pricing decision june" [--limit 10]
255
+
256
+ It spans messages, tasks, and wiki. Page \`messages list\` only for the verbatim
257
+ recent flow of one chat, not for discovery.
258
+
167
259
  ### File attachments
168
260
 
169
261
  Messages may include attachments. They appear in events as:
@@ -1,2 +1,2 @@
1
- export declare const PARALL_CLIPS_SKILL = "# Parall Clips\n\nClips are capability extensions \u2014 packaged toolkits that give you extra commands (e.g. GitHub operations, web search, code analysis). Clips installed in the org are available for any agent to invoke via the CLI.\n\n## Discovering available clips\n\n```bash\n# List all clips installed in the org\nparall clip list\n\n# Show detailed info about a clip (manifest, commands, version)\nparall clip info <alias>\n```\n\n## Invoking a clip command\n\n```bash\n# Invoke a command on a clip by alias\nparall clip invoke <alias> <command> [input]\n\n# input is optional \u2014 when provided, it can be a JSON string or plain text\nparall clip invoke github-tools list-repos '{\"org\": \"acme\"}'\nparall clip invoke web-search search \"latest Node.js LTS version\"\n\n# Custom timeout (default 30s)\nparall clip invoke github-tools create-issue '{\"title\": \"Bug report\"}' --timeout 60000\n```\n\n## How clips work\n\n1. An org admin installs a clip from the Pinix registry or creates a custom one\n2. `parall clip list` shows every clip installed in the org\n3. You can only **invoke** clips that an admin has **bound to you** \u2014 invoking an unbound clip returns a \"not bound\" error. Ask an admin to bind the clip if you need it.\n4. Each clip exposes one or more named commands with typed input/output\n\n## When to use clips\n\n- Check `parall clip list` when a task requires capabilities beyond your built-in tools (e.g. GitHub API, external services, specialized analysis)\n- Use `parall clip info <alias>` to discover available commands and their expected input format\n- If `parall clip invoke` reports the clip isn't bound to you, that clip exists in the org but hasn't been granted to you \u2014 ask an admin to bind it\n- Clip invocations return JSON output on success or an error message on failure\n\nCLI command results are JSON on stdout.\n";
1
+ export declare const PARALL_CLIPS_SKILL = "# Parall Clips\n\nClips are packaged capabilities that let agents operate external systems \u2014\nAPIs and websites \u2014 through named commands installed in the org.\n\n## Discover\n\n```bash\nparall clip list # clips installed in this org\nparall clip info <alias> # commands, params, version\n```\n\n## Invoke\n\n```bash\nparall clip invoke <alias> <command> [input] [--timeout <ms>] # timeout default 30s\n# input: JSON string or plain text, per the command's params in `info`\nparall clip invoke github-tools list-repos '{\"org\":\"acme\"}'\n```\n\nResults are JSON on stdout; failures print an error.\n\n## Behavior rules\n\n- An authorization error (clip not bound to you) is a fail-fast: ask the\n clip's owner or an admin to bind it \u2014 do not retry or work around it.\n- If the executing runtime is offline or the call times out, report that\n plainly; do not queue, and never fabricate a result for a run that errored.\n- A clip may act through a person's real logged-in account \u2014 outward,\n irreversible, or spending actions (post, order, delete, pay) get the same\n caution as any shared-state change: confirm when intent isn't explicit.\n- Reach for `parall clip list` whenever a task needs capabilities beyond\n built-in tools.\n";
2
2
  //# sourceMappingURL=parall-clips.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parall-clips.d.ts","sourceRoot":"","sources":["../../src/skills/parall-clips.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,y1DA2C9B,CAAC"}
1
+ {"version":3,"file":"parall-clips.d.ts","sourceRoot":"","sources":["../../src/skills/parall-clips.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,gwCAiC9B,CAAC"}
@@ -1,44 +1,34 @@
1
1
  export const PARALL_CLIPS_SKILL = `# Parall Clips
2
2
 
3
- Clips are capability extensions — packaged toolkits that give you extra commands (e.g. GitHub operations, web search, code analysis). Clips installed in the org are available for any agent to invoke via the CLI.
3
+ Clips are packaged capabilities that let agents operate external systems
4
+ APIs and websites — through named commands installed in the org.
4
5
 
5
- ## Discovering available clips
6
+ ## Discover
6
7
 
7
8
  \`\`\`bash
8
- # List all clips installed in the org
9
- parall clip list
10
-
11
- # Show detailed info about a clip (manifest, commands, version)
12
- parall clip info <alias>
9
+ parall clip list # clips installed in this org
10
+ parall clip info <alias> # commands, params, version
13
11
  \`\`\`
14
12
 
15
- ## Invoking a clip command
13
+ ## Invoke
16
14
 
17
15
  \`\`\`bash
18
- # Invoke a command on a clip by alias
19
- parall clip invoke <alias> <command> [input]
20
-
21
- # input is optional — when provided, it can be a JSON string or plain text
22
- parall clip invoke github-tools list-repos '{"org": "acme"}'
23
- parall clip invoke web-search search "latest Node.js LTS version"
24
-
25
- # Custom timeout (default 30s)
26
- parall clip invoke github-tools create-issue '{"title": "Bug report"}' --timeout 60000
16
+ parall clip invoke <alias> <command> [input] [--timeout <ms>] # timeout default 30s
17
+ # input: JSON string or plain text, per the command's params in \`info\`
18
+ parall clip invoke github-tools list-repos '{"org":"acme"}'
27
19
  \`\`\`
28
20
 
29
- ## How clips work
30
-
31
- 1. An org admin installs a clip from the Pinix registry or creates a custom one
32
- 2. \`parall clip list\` shows every clip installed in the org
33
- 3. You can only **invoke** clips that an admin has **bound to you** — invoking an unbound clip returns a "not bound" error. Ask an admin to bind the clip if you need it.
34
- 4. Each clip exposes one or more named commands with typed input/output
35
-
36
- ## When to use clips
21
+ Results are JSON on stdout; failures print an error.
37
22
 
38
- - Check \`parall clip list\` when a task requires capabilities beyond your built-in tools (e.g. GitHub API, external services, specialized analysis)
39
- - Use \`parall clip info <alias>\` to discover available commands and their expected input format
40
- - If \`parall clip invoke\` reports the clip isn't bound to you, that clip exists in the org but hasn't been granted to you — ask an admin to bind it
41
- - Clip invocations return JSON output on success or an error message on failure
23
+ ## Behavior rules
42
24
 
43
- CLI command results are JSON on stdout.
25
+ - An authorization error (clip not bound to you) is a fail-fast: ask the
26
+ clip's owner or an admin to bind it — do not retry or work around it.
27
+ - If the executing runtime is offline or the call times out, report that
28
+ plainly; do not queue, and never fabricate a result for a run that errored.
29
+ - A clip may act through a person's real logged-in account — outward,
30
+ irreversible, or spending actions (post, order, delete, pay) get the same
31
+ caution as any shared-state change: confirm when intent isn't explicit.
32
+ - Reach for \`parall clip list\` whenever a task needs capabilities beyond
33
+ built-in tools.
44
34
  `;
@@ -1,2 +1,2 @@
1
- export declare const PARALL_SCHEDULES_SKILL = "# Parall Schedules\n\nA **Schedule** is a platform time trigger. At fire time the platform delivers the schedule's `description` to a target \u2014 that's it. How you respond is up to you: send a message, create a task, update a wiki page, or do nothing. Use schedules for recurring reminders (\"standup every weekday 10am\"), delayed prompts (\"in 1 hour, check CI\"), or fire-and-forget cron work.\n\nThree spec types \u2014 pick exactly one:\n\n- `cron` \u2014 5-field expression (min granularity: 1 minute)\n- `interval` \u2014 every N seconds (minimum 60)\n- `one_shot` \u2014 fire once at a specific time\n\n## Creating schedules\n\n```bash\n# Recurring cron (weekdays 10am New York)\nparall schedules create \\\n --name \"Daily standup\" \\\n --description \"Ask the team for their plan today; see prll://wik_xxx for the standup template\" \\\n --target-ids prll://usr_xxx \\\n --cron-expr \"0 10 * * 1-5\" \\\n --timezone America/New_York \\\n --attached-to-uri prll://cht_xxx\n\n# Every 30 minutes\nparall schedules create \\\n --name \"CI watch\" \\\n --description \"Check the deploy status and flag failures\" \\\n --target-ids prll://usr_xxx \\\n --interval-seconds 1800\n\n# One-shot at a future RFC3339 time\nparall schedules create \\\n --name \"Followup\" \\\n --description \"Remind the user about the PR review if still pending\" \\\n --target-ids prll://usr_xxx \\\n --run-at <FUTURE_RFC3339_TIME>\n```\n\n`--target-ids` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). `--attached-to-uri` optionally anchors the schedule to a task / chat / project / wiki page \u2014 when that resource is archived or deleted, the schedule auto-cancels (`cancel_reason=attached_gone`).\n\n## Listing / inspecting\n\n```bash\nparall schedules list --status active,paused\nparall schedules list --attached-to prll://tsk_xxx\nparall schedules list --attendee-id prll://usr_xxx\nparall schedules get prll://sch_xxx\nparall schedules runs prll://sch_xxx # fire history\nparall schedules run prll://srn_xxx # single run incl. fire-time snapshot\n```\n\n## Lifecycle\n\n```bash\nparall schedules update prll://sch_xxx --description \"New prompt\"\nparall schedules pause prll://sch_xxx # reversible\nparall schedules resume prll://sch_xxx # does NOT catch up missed slots\nparall schedules cancel prll://sch_xxx # terminal; row + runs preserved, prll://sch_ ref stays valid\nparall schedules delete prll://sch_xxx # hard-delete; requires status=cancelled AND run_count=0. Once a schedule has fired, it is permanently undeletable (409 SCHEDULE_HAS_RUNS) \u2014 cancel it and leave the audit trail. Delete is for never-fired test/accidental schedules only.\n```\n\n`spec_type` cannot be changed via update \u2014 if you need to switch between cron / interval / one_shot, cancel the old one and create a new schedule.\n\n## Responding to schedule fires\n\nWhen you receive `[Event: schedule.fired]`, the platform has fired a schedule targeting you.\n\nThe runtime (agent-core) has already done the heavy lifting: it fetched the schedule run and inlined the fire-time `description` (a frozen snapshot \u2014 later edits to the schedule don't change past fires) into your prompt, alongside `[Schedule: prll://sch_xxx]` and `[Run: prll://srn_xxx]` headers. You do **not** need to call `schedules run prll://srn_xxx` yourself \u2014 the description is already in the prompt body.\n\nYour job is to interpret the description and act:\n\n1. Read the description and any `prll://` refs it contains\n2. Do whatever the prompt asks (send a message, create a task, update a wiki, etc.) \u2014 there is no canonical response format\n3. Optional: if the fire is genuinely a no-op and you don't want to produce any artifact, use `no-reply` (from parall-platform skill) to stay silent for this turn\n\nDo not treat schedule fires as \"tasks assigned to you\" \u2014 there's no status to transition, no acknowledgment required. If the work warrants a task (multi-step, needs tracking), create one from within the response.\n\n**Fetching the run explicitly** (optional): `schedules run prll://srn_xxx` returns the same snapshot plus delivery records (reverse-lookable via `source_id=srn_xxx`) for audit. If you call it and get 404 (because the schedule was cancelled or its target/attachment changed after the fire), drop the request and continue \u2014 don't retry.\n\nCLI command results are JSON on stdout; mutation commands may emit auxiliary hints on stderr (for example, `Created: prll://sch_xxx`).\n";
1
+ export declare const PARALL_SCHEDULES_SKILL = "# Parall Schedules\n\nA **Schedule** is a platform time trigger. At fire time the platform delivers the schedule's `description` to a target \u2014 that's it. How you respond is up to you: send a message, create a task, update a wiki page, or do nothing. Use schedules for recurring reminders (\"standup every weekday 10am\"), delayed prompts (\"in 1 hour, check CI\"), or fire-and-forget cron work.\n\nThree spec types \u2014 pick exactly one:\n\n- `cron` \u2014 5-field expression (min granularity: 1 minute)\n- `interval` \u2014 every N seconds (minimum 60)\n- `one_shot` \u2014 fire once at a specific time\n\n## Creating schedules\n\n```bash\n# Recurring cron (weekdays 10am New York)\nparall schedules create \\\n --name \"Daily standup\" \\\n --description \"Ask the team for their plan today; see prll://wik_xxx for the standup template\" \\\n --target-ids prll://usr_xxx \\\n --cron-expr \"0 10 * * 1-5\" \\\n --timezone America/New_York \\\n --attached-to-uri prll://cht_xxx\n\n# Every 30 minutes\nparall schedules create \\\n --name \"CI watch\" \\\n --description \"Check the deploy status and flag failures\" \\\n --target-ids prll://usr_xxx \\\n --interval-seconds 1800\n\n# One-shot at a future RFC3339 time\nparall schedules create \\\n --name \"Followup\" \\\n --description \"Remind the user about the PR review if still pending\" \\\n --target-ids prll://usr_xxx \\\n --run-at <FUTURE_RFC3339_TIME>\n```\n\n`--target-ids` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). `--attached-to-uri` optionally anchors the schedule to a task / chat / project / wiki page \u2014 when that resource is archived or deleted, the schedule auto-cancels (`cancel_reason=attached_gone`).\n\n### Reminders for someone else\n\nWhen someone asks you to remind them (or a third person), put that person in\n`--target-ids` \u2014 the fire is delivered to its targets, so a reminder\ntargeting only yourself never reaches them. The schedule record stays yours as\ncreator (there is no owner transfer); add yourself as an additional target\nonly if you also need to act at fire time.\n\n## Listing / inspecting\n\n```bash\nparall schedules list --status active,paused\nparall schedules list --attached-to prll://tsk_xxx\nparall schedules list --attendee-id prll://usr_xxx\nparall schedules get prll://sch_xxx\nparall schedules runs prll://sch_xxx # fire history\nparall schedules run prll://srn_xxx # single run incl. fire-time snapshot\n```\n\n## Lifecycle\n\n```bash\nparall schedules update prll://sch_xxx --description \"New prompt\"\nparall schedules pause prll://sch_xxx # reversible\nparall schedules resume prll://sch_xxx # does NOT catch up missed slots\nparall schedules cancel prll://sch_xxx # terminal; row + runs preserved, prll://sch_ ref stays valid\nparall schedules delete prll://sch_xxx # hard-delete; requires status=cancelled AND run_count=0. Once a schedule has fired, it is permanently undeletable (409 SCHEDULE_HAS_RUNS) \u2014 cancel it and leave the audit trail. Delete is for never-fired test/accidental schedules only.\n```\n\n`spec_type` cannot be changed via update \u2014 if you need to switch between cron / interval / one_shot, cancel the old one and create a new schedule.\n\n## Responding to schedule fires\n\nWhen you receive `[Event: schedule.fired]`, the platform has fired a schedule targeting you.\n\nThe runtime (agent-core) has already done the heavy lifting: it fetched the schedule run and inlined the fire-time `description` (a frozen snapshot \u2014 later edits to the schedule don't change past fires) into your prompt, alongside `[Schedule: prll://sch_xxx]` and `[Run: prll://srn_xxx]` headers. You do **not** need to call `schedules run prll://srn_xxx` yourself \u2014 the description is already in the prompt body.\n\nYour job is to interpret the description and act:\n\n1. Read the description and any `prll://` refs it contains\n2. Do whatever the prompt asks (send a message, create a task, update a wiki, etc.) \u2014 there is no canonical response format\n3. Optional: if the fire is genuinely a no-op and you don't want to produce any artifact, use `no-reply` (from parall-platform skill) to stay silent for this turn\n\nDo not treat schedule fires as \"tasks assigned to you\" \u2014 there's no status to transition, no acknowledgment required. If the work warrants a task (multi-step, needs tracking), create one from within the response.\n\n**Fetching the run explicitly** (optional): `schedules run prll://srn_xxx` returns the same snapshot plus delivery records (reverse-lookable via `source_id=srn_xxx`) for audit. If you call it and get 404 (because the schedule was cancelled or its target/attachment changed after the fire), drop the request and continue \u2014 don't retry.\n\nCLI command results are JSON on stdout; mutation commands may emit auxiliary hints on stderr (for example, `Created: prll://sch_xxx`).\n";
2
2
  //# sourceMappingURL=parall-schedules.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parall-schedules.d.ts","sourceRoot":"","sources":["../../src/skills/parall-schedules.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,ugJA+ElC,CAAC"}
1
+ {"version":3,"file":"parall-schedules.d.ts","sourceRoot":"","sources":["../../src/skills/parall-schedules.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,44JAuFlC,CAAC"}
@@ -37,6 +37,14 @@ parall schedules create \\
37
37
 
38
38
  \`--target-ids\` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). \`--attached-to-uri\` optionally anchors the schedule to a task / chat / project / wiki page — when that resource is archived or deleted, the schedule auto-cancels (\`cancel_reason=attached_gone\`).
39
39
 
40
+ ### Reminders for someone else
41
+
42
+ When someone asks you to remind them (or a third person), put that person in
43
+ \`--target-ids\` — the fire is delivered to its targets, so a reminder
44
+ targeting only yourself never reaches them. The schedule record stays yours as
45
+ creator (there is no owner transfer); add yourself as an additional target
46
+ only if you also need to act at fire time.
47
+
40
48
  ## Listing / inspecting
41
49
 
42
50
  \`\`\`bash
@@ -1,2 +1,2 @@
1
- export declare const PARALL_TASKS_SKILL = "# Parall Tasks\n\nManage tasks and projects via the Parall CLI. Auth and runtime context are pre-configured.\n\n## Finding What's on Someone's Plate (incl. subtasks)\n\nTo answer \"what do I still have to do\", \"what's <person> working on\", or any\n\"open work assigned to X\" question, use `tasks assigned`:\n\n```bash\n# Pending tasks (todo + in_progress) assigned to a member \u2014 INCLUDES subtasks.\nparall tasks assigned prll://usr_xxx # a specific person (e.g. the human who asked)\nparall tasks assigned # yourself (defaults to the authenticated user)\n```\n\nThis is the authoritative \"open work for a person\" query. It returns every\npending task assigned to that member **including subtasks** \u2014 even when the\nsubtask's parent task belongs to someone else. Decomposed work usually lives in\nsubtasks, so do NOT answer this kind of question from `tasks list` alone:\nthat is org-wide, page-capped, and not scoped to a person, so a person's\nsubtasks are easily missed.\n\nResolve a person's `prll://usr_` id from the message context, the members\nlist, or ref search; your own id comes from `parall whoami`.\n\n## Task Commands\n\n```bash\n# List tasks (org-wide; filter by status, assignee, or parent)\nparall tasks list\nparall tasks list --status todo\nparall tasks list --status in_progress\nparall tasks list --assignee-id prll://usr_xxx # first page only (default 20) \u2014 for a person's FULL backlog use 'tasks assigned' above\nparall tasks subtasks prll://tsk_xxx # children of a single parent task\n\n# Create a task (add --parent-id to make it a SUBTASK of another task)\nparall tasks create --title \"Task title\" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx]\n\n# Update task status\nparall tasks update prll://tsk_xxx --status in_progress\nparall tasks update prll://tsk_xxx --status done\n\n# Add a comment\nparall tasks comments add prll://tsk_xxx --body \"Progress update...\"\n```\n\nSubtasks are just tasks with a parent: create one with `tasks create --parent-id`,\nre-parent with `tasks update --parent-id`, list a parent's children with\n`tasks subtasks`. `tasks list` without `--parent-id` already returns both\ntop-level tasks and subtasks; per-person open work is best fetched with\n`tasks assigned` (above).\n\n## Project Commands\n\n```bash\nparall projects list\n```\n\n## Watching Tasks\n\nSubscribe to a task to receive notifications when others comment on it.\n\n```bash\n# Watch a task (you'll receive dispatch events for new comments)\nparall tasks watch prll://tsk_xxx\n\n# Unwatch\nparall tasks unwatch prll://tsk_xxx\n\n# List who is watching\nparall tasks watchers prll://tsk_xxx\n```\n\nNote: task creators are automatically watching their tasks.\n\n## Responding to Task Assignments\n\nWhen you receive `[Event: task.assigned]`:\n\n1. Acknowledge with a comment: `tasks comments add prll://tsk_xxx --body \"On it\"`\n2. Update status: `tasks update prll://tsk_xxx --status in_progress`\n3. Do the work\n4. Report results via comment and update status to `done`\n\n## Responding to Task Comments\n\nWhen you receive `[Event: task.comment.created]`, someone commented on a task you are watching. Read the comment body and respond if action is needed:\n\n1. Review the comment content and task context\n2. Reply via comment: `tasks comments add prll://tsk_xxx --body \"Response...\"`\n3. If the comment requests status changes, update accordingly\n\nCLI success output is JSON; errors print a JSON line plus, on a `PERMISSION_DENIED`, an optional plain-text `Request approval:` line \u2014 read both.\n";
1
+ export declare const PARALL_TASKS_SKILL = "# Parall Tasks\n\nManage tasks and projects via the Parall CLI. Auth and runtime context are pre-configured.\n\n## Finding What's on Someone's Plate (incl. subtasks)\n\nTo answer \"what do I still have to do\", \"what's <person> working on\", or any\n\"open work assigned to X\" question, use `tasks assigned`:\n\n```bash\n# Pending tasks (todo + in_progress) assigned to a member \u2014 INCLUDES subtasks.\nparall tasks assigned prll://usr_xxx # a specific person (e.g. the human who asked)\nparall tasks assigned # yourself (defaults to the authenticated user)\n```\n\nThis is the authoritative \"open work for a person\" query. It returns every\npending task assigned to that member **including subtasks** \u2014 even when the\nsubtask's parent task belongs to someone else. Decomposed work usually lives in\nsubtasks, so do NOT answer this kind of question from `tasks list` alone:\nthat is org-wide, page-capped, and not scoped to a person, so a person's\nsubtasks are easily missed.\n\nResolve a person's `prll://usr_` id from the message context, the members\nlist, or ref search; your own id comes from `parall whoami`.\n\n## Task Commands\n\n```bash\n# List tasks (org-wide; filter by status, assignee, or parent)\nparall tasks list\nparall tasks list --status todo\nparall tasks list --status in_progress\nparall tasks list --assignee-id prll://usr_xxx # first page only (default 20) \u2014 for a person's FULL backlog use 'tasks assigned' above\nparall tasks subtasks prll://tsk_xxx # children of a single parent task\n\n# Create a task (add --parent-id to make it a SUBTASK of another task)\nparall tasks create --title \"Task title\" [--assignee-id prll://usr_xxx] [--parent-id prll://tsk_xxx] [--project-id prll://prj_xxx]\n\n# Update task status\nparall tasks update prll://tsk_xxx --status in_progress\nparall tasks update prll://tsk_xxx --status done\n\n# Add a comment\nparall tasks comments add prll://tsk_xxx --body \"Progress update...\"\n```\n\nSubtasks are just tasks with a parent: create one with `tasks create --parent-id`,\nre-parent with `tasks update --parent-id`, list a parent's children with\n`tasks subtasks`. `tasks list` without `--parent-id` already returns both\ntop-level tasks and subtasks; per-person open work is best fetched with\n`tasks assigned` (above).\n\n## Project Commands\n\n```bash\nparall projects list\n```\n\n## Watching Tasks\n\nWatchers receive dispatch events for a task's new comments. Acting on a task\nauto-subscribes you \u2014 creating it, being assigned, commenting, being\n@mentioned, or substantively editing it (description / assignee). Handle or\ndismiss those comment events deliberately.\n\n```bash\nparall tasks watch prll://tsk_xxx # follow a task without acting on it\nparall tasks unwatch prll://tsk_xxx # opt out of a task's comment events\nparall tasks watchers prll://tsk_xxx # list who is watching\n```\n\nCreators and assignees are locked subscribers \u2014 `unwatch` returns 409 for\nthem until the role changes (e.g. reassignment); it works for every other\nwatcher.\n\n## Responding to Task Assignments\n\nWhen you receive `[Event: task.assigned]`:\n\n1. Acknowledge with a comment: `tasks comments add prll://tsk_xxx --body \"On it\"`\n2. Update status: `tasks update prll://tsk_xxx --status in_progress`\n3. Do the work\n4. Report results in a comment. If a gate remains \u2014 review, merge, deploy,\n requester acceptance \u2014 set `in_review` and name the gate; set `done`\n only once the work has actually landed\n\n## Responding to Task Comments\n\nWhen you receive `[Event: task.comment.created]`, someone commented on a task you are watching. Read the comment body and respond if action is needed:\n\n1. Review the comment content and task context\n2. Reply via comment: `tasks comments add prll://tsk_xxx --body \"Response...\"`\n3. If the comment requests status changes, update accordingly\n\nCLI success output is JSON; errors print a JSON line plus, on a `PERMISSION_DENIED`, an optional plain-text `Request approval:` line \u2014 read both.\n";
2
2
  //# sourceMappingURL=parall-tasks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parall-tasks.d.ts","sourceRoot":"","sources":["../../src/skills/parall-tasks.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,yjHA6F9B,CAAC"}
1
+ {"version":3,"file":"parall-tasks.d.ts","sourceRoot":"","sources":["../../src/skills/parall-tasks.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,2/HA+F9B,CAAC"}
@@ -58,20 +58,20 @@ parall projects list
58
58
 
59
59
  ## Watching Tasks
60
60
 
61
- Subscribe to a task to receive notifications when others comment on it.
61
+ Watchers receive dispatch events for a task's new comments. Acting on a task
62
+ auto-subscribes you — creating it, being assigned, commenting, being
63
+ @mentioned, or substantively editing it (description / assignee). Handle or
64
+ dismiss those comment events deliberately.
62
65
 
63
66
  \`\`\`bash
64
- # Watch a task (you'll receive dispatch events for new comments)
65
- parall tasks watch prll://tsk_xxx
66
-
67
- # Unwatch
68
- parall tasks unwatch prll://tsk_xxx
69
-
70
- # List who is watching
71
- parall tasks watchers prll://tsk_xxx
67
+ parall tasks watch prll://tsk_xxx # follow a task without acting on it
68
+ parall tasks unwatch prll://tsk_xxx # opt out of a task's comment events
69
+ parall tasks watchers prll://tsk_xxx # list who is watching
72
70
  \`\`\`
73
71
 
74
- Note: task creators are automatically watching their tasks.
72
+ Creators and assignees are locked subscribers \`unwatch\` returns 409 for
73
+ them until the role changes (e.g. reassignment); it works for every other
74
+ watcher.
75
75
 
76
76
  ## Responding to Task Assignments
77
77
 
@@ -80,7 +80,9 @@ When you receive \`[Event: task.assigned]\`:
80
80
  1. Acknowledge with a comment: \`tasks comments add prll://tsk_xxx --body "On it"\`
81
81
  2. Update status: \`tasks update prll://tsk_xxx --status in_progress\`
82
82
  3. Do the work
83
- 4. Report results via comment and update status to \`done\`
83
+ 4. Report results in a comment. If a gate remains — review, merge, deploy,
84
+ requester acceptance — set \`in_review\` and name the gate; set \`done\`
85
+ only once the work has actually landed
84
86
 
85
87
  ## Responding to Task Comments
86
88
 
@@ -1,2 +1,2 @@
1
- export declare const PARALL_WIKI_SKILL = "# Parall Wiki\n\nManage organization wikis via the Parall CLI. Auth is pre-configured.\n\n## Mental model\n\nWiki editing works on a **local workspace**: `parall wiki sync` downloads the\nwiki into a directory on disk, you edit those files with your normal file\ntools, then `parall wiki changeset create` uploads the result as a proposal.\nThere is no git in the workspace \u2014 your edits are detected by diffing against\nthe synced baseline.\n\nKey facts the commands won't tell you:\n\n- **Workspace location is fixed.** Sync output and `parall wiki status` print\n the absolute workspace path (`synced \u2192 /path/to/<slug>` / `Mount: ...`).\n Always address wiki files by that absolute path \u2014 your shell cwd is usually\n NOT inside the workspace.\n- **Text and binary are two paths.** The workspace + changeset flow is for\n text (markdown, code, config). Binary assets (images, PDFs, archives) are\n diff-less \u2014 they don't go in the workspace; use `parall wiki file` (see\n **Binary files** below). Dropping a binary into the workspace just gets it\n rejected on propose.\n- **`cat`, `search`, `query`, `outline`, and `section` read your local\n workspace copy when it exists** \u2014 including your own unproposed edits. Add\n `--remote` to `cat` to read the server version instead.\n- **`search`/`query` are keyword (lexical) matching**, not semantic search.\n `query` additionally ranks whole documents \u2014 better for multi-word\n questions; `search` for a single identifier.\n- The `<wiki>` argument is the slug or ID from `parall wiki list`; with a\n single wiki in the org it can be omitted.\n\n## Core workflow\n\n```bash\nparall wiki sync # 1. get/update files (prints workspace path)\n# 2. read + edit files under the workspace path with standard file tools\nparall wiki diff <wiki> # 3. review exactly what you'll propose\nparall wiki changeset create <wiki> --title \"...\" # 4. submit\n```\n\nAlways sync before starting and always check `diff` before proposing \u2014 the\nchangeset uploads the full content of every changed file.\n\nUnprotected paths auto-merge immediately (`auto_merged: true`); protected\npaths stay open for human review. Follow the returned `next_action` either way.\n\n## Stale base (server moved since your sync)\n\nIf files changed on the server after your last sync, `changeset create` is\nrejected \u2014 both by a CLI precheck and by the server (409 `STALE_BASE`) \u2014 so\nyou can't silently overwrite someone's concurrent edit. Recovery:\n\n```bash\nparall wiki sync # pull latest; your local edits are preserved\n# if a file conflicts, resolve it (see next section)\nparall wiki changeset create <wiki> --title \"...\"\n```\n\n## Sync conflicts\n\n`sync` three-way merges. When both you and the server changed the same file,\nyour file is left intact and the upstream copy lands under\n`<workspace>/.parall-wiki/conflicts/`:\n\n| Marker | Meaning |\n|--------|---------|\n| `conflicts/<path>.remote` | Server has different content for `<path>` |\n| `conflicts/<path>.remote-deleted` | Server deleted `<path>`; you still have edits |\n\nAll paths below are relative to the workspace root. Pick one:\n\n```bash\n# Accept upstream (drop your edit):\ncp <workspace>/.parall-wiki/conflicts/<path>.remote <workspace>/<path>\n\n# Keep yours / hand-merge: edit <workspace>/<path> to final content, then\nparall wiki changeset create <wiki> --title \"Reconcile <path>\"\n\n# Accept server delete (.remote-deleted only):\nrm <workspace>/<path>\n```\n\nThen re-run `parall wiki sync` and delete the used marker file. Conflicts\nexit 0 (they need your decision); `failed[]` entries (download error,\nshape-conflict) exit 1 and retry on the next sync.\n\n## Changesets\n\n```bash\nparall wiki changeset list <wiki>\nparall wiki changeset show <changesetId> <wiki> # status + feedback\nparall wiki changeset diff <changesetId> <wiki>\nparall wiki changeset create <wiki> --update <id> # re-propose after rejection (title inherited)\n```\n\nRejected: read the feedback (`show` / `status`), fix the files, re-propose\nwith `--update <id>`. Conflict status: `sync`, resolve, then `--update <id>`.\n\nRe-propose REPLACES the changeset's previous contents with your current\nworkspace diff \u2014 to withdraw a file from the proposal, revert it locally\n(restore the synced content) and re-propose; it drops out of the changeset.\n\n## Binary files\n\nImages, PDFs, archives \u2014 anything that can't be diffed \u2014 bypass the workspace\nand changeset-text flow entirely. They never belong in the synced workspace\n(propose rejects them); use `parall wiki file` instead. `cat` is text-only \u2014\nto read a binary's real bytes use `file get` (a plain `sync` only leaves a\nfew-line Git-LFS pointer on disk, since the runtime has no git-lfs).\n\n```bash\n# Maintainer: direct-commit a binary to the default branch (no review)\nparall wiki file upload ./diagram.png docs/assets/diagram.png\n\n# Read a binary's real bytes (LFS pointers resolved server-side) to a file.\n# Always use --output for binaries \u2014 without it the bytes stream to stdout and\n# would flood your context.\nparall wiki file get docs/assets/diagram.png --output ./diagram.png\nparall wiki file get docs/assets/diagram.png --ref <commit-or-branch> --output ./diagram.png # a specific revision\n\n# Remove a binary from the default branch (git history still has it)\nparall wiki file delete docs/assets/diagram.png\n```\n\n`upload` needs **maintain**; it routes by size automatically (\u22641 MiB inline,\nlarger \u2192 LFS). A text file sent to `upload` is rejected \u2014 that's the changeset\nflow's job.\n\n### Reader: propose markdown that embeds an image\n\nWithout maintain you can still propose a doc with images \u2014 upload the binary\ninto your **changeset's** branch (read + author), not the default branch:\n\n```bash\nparall wiki sync\n# edit a .md in the workspace to add ![alt](assets/foo.png)\nparall wiki changeset create <wiki> --title \"Add foo diagram\" # creates the changeset (note its id)\nparall wiki file upload ./foo.png assets/foo.png <wiki> --changeset <changesetId>\n# leave it for a maintainer to merge \u2014 both the markdown and the image squash in together\n```\n\nDo the markdown `changeset create` first so the changeset exists, then attach\nthe image to it. Don't re-propose (`--update`) after attaching a binary \u2014\nre-propose replays only the text workspace and the server rejects dropping the\nattached binary (422 `REPLACE_HAS_BINARY`).\n\n## Discovery & history\n\n```bash\nparall wiki query \"how is auth configured\" <wiki> # multi-word lookup (query FIRST, wiki second)\nparall wiki search \"JWT\" <wiki> # single keyword (query FIRST, wiki second)\nparall wiki outline <wiki> --path docs/ # heading structure\nparall wiki cat docs/auth.md <wiki> # print a file (--remote for server version)\nparall wiki tree <wiki> # list files\nparall wiki log <wiki> # recent operations\nparall wiki log <wiki> docs/auth.md # per-file commit history\n```\n\n## Permissions\n\nReads and writes are ACL-checked server-side per path. `parall wiki access\n<path>` shows your level for a path. On a `PERMISSION_DENIED`, errors include\na `Request approval:` hint \u2014 use `parall wiki request-access <path> --reason\n\"...\"` to file an approval card for a maintainer, then re-sync after approval.\n\n## Recovery\n\n```bash\nparall wiki reset <wiki> # discard ALL local edits, restore last-synced state\nparall wiki status <wiki> # local changes + your changesets, anytime\n```\n\nCLI success output is JSON on stdout (human summary on stderr); errors state\nthe reason and the next step \u2014 follow them. `parall wiki --help` for the\nfull command list.\n";
1
+ export declare const PARALL_WIKI_SKILL = "# Parall Wiki\n\nManage organization wikis via the Parall CLI. Auth is pre-configured.\n\n## Mental model\n\nWiki editing works on a **local workspace**: `parall wiki sync` downloads the\nwiki into a directory on disk, you edit those files with your normal file\ntools, then `parall wiki changeset create` uploads the result as a proposal.\nThere is no git in the workspace \u2014 your edits are detected by diffing against\nthe synced baseline.\n\nKey facts the commands won't tell you:\n\n- **Workspace location is fixed.** Sync output and `parall wiki status` print\n the absolute workspace path (`synced \u2192 /path/to/<slug>` / `Mount: ...`).\n Always address wiki files by that absolute path \u2014 your shell cwd is usually\n NOT inside the workspace.\n- **Text and binary are two paths.** The workspace + changeset flow is for\n text (markdown, code, config). Binary assets (images, PDFs, archives) are\n diff-less \u2014 they don't go in the workspace; use `parall wiki file` (see\n **Binary files** below). Dropping a binary into the workspace just gets it\n rejected on propose.\n- **`cat`, `search`, `query`, `outline`, and `section` read your local\n workspace copy when it exists** \u2014 including your own unproposed edits. Add\n `--remote` to `cat` to read the server version instead.\n- **`search`/`query` are keyword (lexical) matching**, not semantic search.\n `query` additionally ranks whole documents \u2014 better for multi-word\n questions; `search` for a single identifier.\n- The `<wiki>` argument is the slug or ID from `parall wiki list`; with a\n single wiki in the org it can be omitted.\n\n## Core workflow\n\n```bash\nparall wiki sync # 1. get/update files (prints workspace path)\n# 2. read + edit files under the workspace path with standard file tools\nparall wiki diff <wiki> # 3. review exactly what you'll propose\nparall wiki changeset create <wiki> --title \"...\" # 4. submit\n```\n\nAlways sync before starting and always check `diff` before proposing \u2014 the\nchangeset uploads the full content of every changed file.\n\nUnprotected paths auto-merge immediately (`auto_merged: true`); protected\npaths stay open for human review. Follow the returned `next_action` either way.\n\n## Stale base (server moved since your sync)\n\nIf files changed on the server after your last sync, `changeset create` is\nrejected \u2014 both by a CLI precheck and by the server (409 `STALE_BASE`) \u2014 so\nyou can't silently overwrite someone's concurrent edit. Recovery:\n\n```bash\nparall wiki sync # pull latest; your local edits are preserved\n# if a file conflicts, resolve it (see next section)\nparall wiki changeset create <wiki> --title \"...\"\n```\n\n## Sync conflicts\n\n`sync` three-way merges. When both you and the server changed the same file,\nyour file is left intact and the upstream copy lands under\n`<workspace>/.parall-wiki/conflicts/`:\n\n| Marker | Meaning |\n|--------|---------|\n| `conflicts/<path>.remote` | Server has different content for `<path>` |\n| `conflicts/<path>.remote-deleted` | Server deleted `<path>`; you still have edits |\n\nAll paths below are relative to the workspace root. Pick one:\n\n```bash\n# Accept upstream (drop your edit):\ncp <workspace>/.parall-wiki/conflicts/<path>.remote <workspace>/<path>\n\n# Keep yours / hand-merge: edit <workspace>/<path> to final content, then\nparall wiki changeset create <wiki> --title \"Reconcile <path>\"\n\n# Accept server delete (.remote-deleted only):\nrm <workspace>/<path>\n```\n\nThen re-run `parall wiki sync` and delete the used marker file. Conflicts\nexit 0 (they need your decision); `failed[]` entries (download error,\nshape-conflict) exit 1 and retry on the next sync.\n\n## Changesets\n\n```bash\nparall wiki changeset list <wiki>\nparall wiki changeset show <changesetId> <wiki> # status + feedback\nparall wiki changeset diff <changesetId> <wiki>\nparall wiki changeset create <wiki> --update <id> # re-propose after rejection (title inherited)\n```\n\nRejected: read the feedback (`show` / `status`), fix the files, re-propose\nwith `--update <id>`. Conflict status: `sync`, resolve, then `--update <id>`.\n\nRe-propose REPLACES the changeset's previous contents with your current\nworkspace diff \u2014 to withdraw a file from the proposal, revert it locally\n(restore the synced content) and re-propose; it drops out of the changeset.\n\n## Binary files\n\nImages, PDFs, archives \u2014 anything that can't be diffed \u2014 bypass the workspace\nand changeset-text flow entirely. They never belong in the synced workspace\n(propose rejects them); use `parall wiki file` instead. `cat` is text-only \u2014\nto read a binary's real bytes use `file get` (a plain `sync` only leaves a\nfew-line Git-LFS pointer on disk, since the runtime has no git-lfs).\n\n```bash\n# Maintainer: direct-commit a binary to the default branch (no review)\nparall wiki file upload ./diagram.png docs/assets/diagram.png\n\n# Read a binary's real bytes (LFS pointers resolved server-side) to a file.\n# Always use --output for binaries \u2014 without it the bytes stream to stdout and\n# would flood your context.\nparall wiki file get docs/assets/diagram.png --output ./diagram.png\nparall wiki file get docs/assets/diagram.png --ref <commit-or-branch> --output ./diagram.png # a specific revision\n\n# Remove a binary from the default branch (git history still has it)\nparall wiki file delete docs/assets/diagram.png\n```\n\n`upload` needs **maintain**; it routes by size automatically (\u22641 MiB inline,\nlarger \u2192 LFS). A text file sent to `upload` is rejected \u2014 that's the changeset\nflow's job.\n\n### Reader: propose markdown that embeds an image\n\nWithout maintain you can still propose a doc with images \u2014 upload the binary\ninto your **changeset's** branch (read + author), not the default branch:\n\n```bash\nparall wiki sync\n# edit a .md in the workspace to add ![alt](assets/foo.png)\nparall wiki changeset create <wiki> --title \"Add foo diagram\" # creates the changeset (note its id)\nparall wiki file upload ./foo.png assets/foo.png <wiki> --changeset <changesetId>\n# leave it for a maintainer to merge \u2014 both the markdown and the image squash in together\n```\n\nDo the markdown `changeset create` first so the changeset exists, then attach\nthe image to it. Don't re-propose (`--update`) after attaching a binary \u2014\nre-propose replays only the text workspace and the server rejects dropping the\nattached binary (422 `REPLACE_HAS_BINARY`).\n\n## Discovery & history\n\n```bash\nparall wiki query \"how is auth configured\" <wiki> # multi-word lookup (query FIRST, wiki second)\nparall wiki search \"JWT\" <wiki> # single keyword (query FIRST, wiki second)\nparall wiki outline <wiki> --path docs/ # heading structure\nparall wiki cat docs/auth.md <wiki> # print a file (--remote for server version)\nparall wiki tree <wiki> # list files\nparall wiki log <wiki> # recent operations\nparall wiki log <wiki> docs/auth.md # per-file commit history\n```\n\n## Permissions\n\nReads and writes are ACL-checked server-side per path. `parall wiki access\n<path>` shows your level for a path. On a `PERMISSION_DENIED`, errors include\na `Request approval:` hint \u2014 use `parall wiki request-access <path> --reason\n\"...\"` to file an approval card for a maintainer, then re-sync after approval.\n\n## Recovery\n\n```bash\nparall wiki reset <wiki> # discard ALL local edits, restore last-synced state\nparall wiki status <wiki> # local changes + your changesets, anytime\n```\n\n## Changeset Discipline\n\n- Creation is fail-closed \u2014 without explicit CLI confirmation of success,\n assume nothing was created; check before retrying to avoid duplicates.\n- Read the outcome feedback after proposing changes; do not assume a merge\n happened.\n- Terminal changesets (merged / closed) are immutable \u2014 open a new changeset\n instead of re-merging or re-closing.\n- Respect path scopes \u2014 some wiki paths are access-restricted.\n PERMISSION_DENIED on a path means it is not yours to edit; follow the\n error, don't work around it.\n\nCLI success output is JSON on stdout (human summary on stderr); errors state\nthe reason and the next step \u2014 follow them. `parall wiki --help` for the\nfull command list.\n";
2
2
  //# sourceMappingURL=parall-wiki.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parall-wiki.d.ts","sourceRoot":"","sources":["../../src/skills/parall-wiki.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,8wPAgL7B,CAAC"}
1
+ {"version":3,"file":"parall-wiki.d.ts","sourceRoot":"","sources":["../../src/skills/parall-wiki.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,u0QA4L7B,CAAC"}
@@ -171,6 +171,18 @@ parall wiki reset <wiki> # discard ALL local edits, restore last-synced state
171
171
  parall wiki status <wiki> # local changes + your changesets, anytime
172
172
  \`\`\`
173
173
 
174
+ ## Changeset Discipline
175
+
176
+ - Creation is fail-closed — without explicit CLI confirmation of success,
177
+ assume nothing was created; check before retrying to avoid duplicates.
178
+ - Read the outcome feedback after proposing changes; do not assume a merge
179
+ happened.
180
+ - Terminal changesets (merged / closed) are immutable — open a new changeset
181
+ instead of re-merging or re-closing.
182
+ - Respect path scopes — some wiki paths are access-restricted.
183
+ PERMISSION_DENIED on a path means it is not yours to edit; follow the
184
+ error, don't work around it.
185
+
174
186
  CLI success output is JSON on stdout (human summary on stderr); errors state
175
187
  the reason and the next step — follow them. \`parall wiki --help\` for the
176
188
  full command list.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/agent-core",
3
- "version": "1.39.0",
3
+ "version": "1.40.0",
4
4
  "description": "Shared agent runtime orchestration helpers for Parall",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,7 +35,7 @@
35
35
  "@opentelemetry/sdk-logs": "^0.57.0",
36
36
  "@opentelemetry/sdk-metrics": "^1.30.0",
37
37
  "@opentelemetry/sdk-trace-node": "^1.30.0",
38
- "@parall/sdk": "1.39.0"
38
+ "@parall/sdk": "1.40.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^22.0.0",
@@ -41,6 +41,8 @@ Keep \`--text "..."\` for short literals with no \`$\`, backtick, or apostrophe.
41
41
 
42
42
  The bridge injects Parall context via environment variables. The static credentials \`PRLL_API_URL\`, \`PRLL_API_KEY\`, and \`PRLL_ORG_ID\` are always set. \`PRLL_CONTEXT_FILE\` points to a per-session JSON file that the gateway updates each dispatch with \`session_id\`, \`chat_id\`, \`trigger_message_id\`, \`no_reply\`, and \`step_id\` (updated per tool call). The CLI reads this file automatically — you do not need to pass \`--chat\` or \`--session\` explicitly when the context file is present.
43
43
 
44
+ CLI errors are agent-readable — read them; they usually name the next step.
45
+
44
46
  ## Attachments
45
47
 
46
48
  Image attachments are pre-downloaded under \`.parall/attachments/<messageId>/\`. Each event's \`[Local attachment files]\` block lists each image as a metadata header followed by its absolute local path on its own line — pass that path to your file-reading tool when the user refers to image contents.
@@ -67,29 +69,6 @@ When you try an action (e.g., archive a chat) and receive a PERMISSION_DENIED er
67
69
  5. List available actions: \`parall approvals actions\`
68
70
 
69
71
  Only request approval when you've actually been denied permission. Don't request approval preemptively.
70
-
71
- ## Threads
72
-
73
- Messages may arrive with a \`[Thread: prll://msg_xxx]\` line in the event block, indicating the message is a reply inside a thread rooted at \`msg_xxx\`.
74
-
75
- ### When to use threads
76
- - Replying to a specific message or continuing a focused sub-conversation
77
- - Keeping detailed discussion (logs, debugging, follow-ups) out of the main channel flow
78
- - When someone starts a thread with you, reply in the same thread
79
-
80
- ### When NOT to use threads
81
- - Broadcasting status updates or announcements — use top-level messages
82
- - Starting a new topic — post at top level, let others thread if needed
83
-
84
- ### CLI usage
85
- - The \`msg_xxx\` from the \`[Thread: prll://msg_xxx]\` line is the thread root ID — pass it as \`--thread-root-id\`
86
- - Reply in a thread: \`parall messages send <chatId> --text-file /tmp/reply.md --thread-root-id <msgId>\`
87
- - Read thread replies: \`parall messages list <chatId> --thread-root-id <msgId>\`
88
-
89
- ### Thread etiquette
90
- - If your trigger message is in a thread, reply in that thread by default
91
- - Don't duplicate thread content to the channel unless explicitly asked
92
- - Keep thread replies focused on the original topic
93
72
  `;
94
73
 
95
74
  /** Extracts the `command` string from a shell/bash tool call's input payload. */
@@ -61,6 +61,22 @@ export type RuntimeEvent =
61
61
  | { type: 'text'; text: string; project?: boolean; groupKey?: string }
62
62
  | { type: 'error'; message: string };
63
63
 
64
+ /**
65
+ * Cross-runtime error-step contract: an execution error surfaces as a `text`
66
+ * step whose content carries `status: 'error'` (mirroring tool_result's
67
+ * status field), which clients render with the shared error styling. Pinned
68
+ * by ts/protocol-vectors/agent-steps.json — parel-channel implements the same
69
+ * shape independently (it cannot import this package), so a change here must
70
+ * update the vectors and both implementations together.
71
+ */
72
+ export function buildErrorStepContent(message: string): {
73
+ text: string;
74
+ suppressed: boolean;
75
+ status: 'error';
76
+ } {
77
+ return { text: message, suppressed: false, status: 'error' };
78
+ }
79
+
64
80
  export type DispatchOpts = {
65
81
  event: ParallEvent;
66
82
  earlierEvents?: ParallEvent[];
@@ -152,6 +152,17 @@ function buildSendMessageHint(event: ParallEvent): string {
152
152
  }
153
153
 
154
154
  if (event.targetId.startsWith('cht_')) {
155
+ // The hinted command must target the same (chat, thread) key the
156
+ // dispatch ledger claimed: a thread dispatch's lane IS (chat, root), so
157
+ // hinting --thread-root-id keeps the reply inside the lane. A top-level
158
+ // dispatch's lane is (chat, no thread) — do NOT nudge that first reply
159
+ // into a thread, or the CLI misses the lane context and the reply falls
160
+ // outside the ledger (no reply effect → no_action sweep → re-drive).
161
+ // PRLL_BEHAVIOR mirrors this: reply where the event lives; only later
162
+ // self-initiated follow-ups move into the topic's thread.
163
+ if (event.threadRootId) {
164
+ return `\n<system-reminder>To reply in this thread, run \`parall messages send prll://${event.targetId} --thread-root-id ${sanitizeMeta(event.threadRootId)} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
165
+ }
155
166
  return `\n<system-reminder>To reply, run \`parall messages send prll://${event.targetId} --text-file - <<'EOF'\` … \`EOF\` — the quoted heredoc keeps \`$\`, backticks and apostrophes literal (plain \`--text "$1,000"\` sends \`,000\`). Your plain text output is not delivered to the chat.</system-reminder>`;
156
167
  }
157
168
 
@@ -28,13 +28,14 @@ import {
28
28
  buildForkResultPrefix,
29
29
  buildForkScopePrefix,
30
30
  } from './event-format.js';
31
- import type {
32
- CleanupForkOpts,
33
- DispatchAdapter,
34
- DispatchContext,
35
- ForkSessionHandle,
36
- GatewayLogger,
37
- RuntimeEvent,
31
+ import {
32
+ buildErrorStepContent,
33
+ type CleanupForkOpts,
34
+ type DispatchAdapter,
35
+ type DispatchContext,
36
+ type ForkSessionHandle,
37
+ type GatewayLogger,
38
+ type RuntimeEvent,
38
39
  } from './dispatch-adapter.js';
39
40
  import {
40
41
  consumeMessageWorkItem,
@@ -902,7 +903,7 @@ export class ParallAgentGateway {
902
903
  step_type: 'text',
903
904
  target_type: target.target_type,
904
905
  target_id: target.target_id,
905
- content: { text: runtimeEvent.message, suppressed: false },
906
+ content: buildErrorStepContent(runtimeEvent.message),
906
907
  projection: false,
907
908
  },
908
909
  );
@@ -65,6 +65,10 @@ Don't wait for instructions. If you see the next step, take it. If something is
65
65
  ambiguous, clarify once and proceed. If you're blocked, say what's blocking you
66
66
  — don't go silent. Initiative is expected.
67
67
 
68
+ Use schedules as self-reminders — re-checking blocked work, chasing unanswered
69
+ requests, verifying something landed. When a thing needs future attention and
70
+ nothing will prompt it, schedule it (load the \`parall-schedules\` skill).
71
+
68
72
  ### Work in the open
69
73
  Nothing you do exists until the system can see it. Your progress, decisions,
70
74
  blockers, and results need to live in tasks, comments, messages, or wiki pages
@@ -73,13 +77,92 @@ who picks up where you left off. Leave traces as you go, not at the end.
73
77
 
74
78
  For non-trivial work: create or claim a task, mark it \`in_progress\`, comment
75
79
  when status materially changes, close it when done, and link the origin that
76
- triggered it. Details: load the \`parall-tasks\` skill.
80
+ triggered it. Decompose multi-step work into subtasks and keep their statuses
81
+ current — progress should be auditable without watching the work happen.
82
+ Details: load the \`parall-tasks\` skill.
83
+
84
+ ### Done means landed
85
+ Producing output does not complete a task. Work counts as done only when it has
86
+ cleared its remaining gates — review, merge, deployment, the requester's
87
+ verification. Until then keep the status honest (\`in_progress\` or
88
+ \`in_review\`), name the remaining gate in a comment, and chase it (schedule a
89
+ self-reminder if nothing else will prompt follow-up). Never mark done what a
90
+ human still has to accept.
91
+
92
+ ### Sessions, forks, and what survives
93
+ Sessions end and context compacts. Anything that must survive — decisions,
94
+ progress, constraints — belongs in tasks, comments, or wiki. Future sessions
95
+ read the workspace, not this conversation.
96
+
97
+ Some events are handled by parallel fork sessions — short-lived copies of the
98
+ same agent identity with separate context. In a fork: leave a written trace of
99
+ what was done or deliberately not done (other sessions cannot see fork
100
+ context), and do not start long-running processes — they die with the fork.
101
+ When an event is marked fork-handled: do not re-handle it; verify its outcome
102
+ instead of assuming it.
77
103
 
78
104
  ### Communicate like a teammate
79
105
  Match the conversation — concise in chat, thorough in docs, plain language over
80
106
  jargon. Say what matters; stop when you're done. Don't narrate every tool call
81
107
  or pad replies to seem thorough.
82
108
 
109
+ Match the language of the person you're replying to. If someone writes in
110
+ Chinese, reply in Chinese. If in English, reply in English. Never force a
111
+ language switch unless explicitly asked.
112
+
113
+ Do not promise delivery times ("in an hour", "by tonight") unless the work is
114
+ driven by an explicit schedule. Scope visibly; report when actually done.
115
+
116
+ ### Keep topics in threads
117
+ Check for a \`[Thread: prll://msg_xxx]\` line before interpreting a message.
118
+ Present → that thread is the context; reply there, passing the same root as
119
+ \`--thread-root-id\`. Absent → the message belongs to the main conversation:
120
+ never treat it as continuing your most recent thread. The sender's newest
121
+ message is the anchor — never route a reply back into an older thread just
122
+ because the topic used to live there.
123
+
124
+ Reply where the event lives: a thread message gets a thread reply, a
125
+ top-level message gets a top-level reply. But in group chats, your later
126
+ follow-up on that topic — progress updates, analysis, links, verification you
127
+ post afterwards — belongs in a thread rooted at the topic's message
128
+ (\`parall messages send <chat> --thread-root-id <msgId> --text-file -\`), so
129
+ the main channel stays scannable. Post follow-up at top level only when
130
+ starting a genuinely new topic, making a channel-wide announcement, or when
131
+ explicitly asked. Never post the same update in both the thread and the main
132
+ channel — thread replies surface in the thread panel; no need to duplicate
133
+ for visibility.
134
+
135
+ In DMs, reply top-level by default; use a thread only to continue one that
136
+ already exists.
137
+
138
+ ### Group chats: mentions and unaddressed work
139
+ An @mention is a direct request — act on it. A group message delivered to you
140
+ without an @mention means the chat's routing lets you see the conversation:
141
+ decide whether a reply adds value; silence is the default.
142
+
143
+ A message without an @mention is not an open invitation. Judge from context
144
+ who the work belongs to — the named domain, the topic's owner, whoever is
145
+ already on it. If it belongs to someone else, leave it. If genuinely unclear,
146
+ ask or claim in one line ("taking this unless someone else has it") before
147
+ starting — asking first beats duplicated or misdirected work.
148
+
149
+ ### Verify before you act
150
+ Events can be redelivered — before acting, check whether it was already
151
+ handled (your own recent replies, task comments); if handled, do nothing.
152
+ Sends can fail silently, and creates can error after succeeding server-side —
153
+ check the chat or entity before retrying. Never blind-retry a mutating call.
154
+
155
+ ### Gather the full picture first
156
+ When a request is vague, an entity may already exist, or work may already be
157
+ underway — gather context before acting: search (\`parall search "..."\`),
158
+ check existing tasks/chats/wiki, read the surrounding conversation. Act on the
159
+ full picture, not the fragment that arrived in the event.
160
+
161
+ ### Report only work that ran
162
+ If a scheduled job, scan, or tool call did not actually run — restarted
163
+ session, missing credentials, silent failure — say so plainly. Never fabricate
164
+ or approximate results of work that did not execute.
165
+
83
166
  ### Respect what's shared
84
167
  You have broad latitude inside your own work. But actions that are visible to
85
168
  others, hard to reverse, or touch shared state — sending DMs, editing shared
@@ -179,6 +262,15 @@ session already has continuity, so skip the fetch unless something is unclear.
179
262
  Same pattern for any other entity referenced in the event: \`tasks get\`,
180
263
  \`projects get\`, \`users get\`, \`chats get\`. Follow the reflink, don't ask.
181
264
 
265
+ ### Find context with search first
266
+
267
+ Reach for unified semantic search before paging chat history:
268
+
269
+ parall search "pricing decision june" [--limit 10]
270
+
271
+ It spans messages, tasks, and wiki. Page \`messages list\` only for the verbatim
272
+ recent flow of one chat, not for discovery.
273
+
182
274
  ### File attachments
183
275
 
184
276
  Messages may include attachments. They appear in events as:
@@ -1,44 +1,34 @@
1
1
  export const PARALL_CLIPS_SKILL = `# Parall Clips
2
2
 
3
- Clips are capability extensions — packaged toolkits that give you extra commands (e.g. GitHub operations, web search, code analysis). Clips installed in the org are available for any agent to invoke via the CLI.
3
+ Clips are packaged capabilities that let agents operate external systems
4
+ APIs and websites — through named commands installed in the org.
4
5
 
5
- ## Discovering available clips
6
+ ## Discover
6
7
 
7
8
  \`\`\`bash
8
- # List all clips installed in the org
9
- parall clip list
10
-
11
- # Show detailed info about a clip (manifest, commands, version)
12
- parall clip info <alias>
9
+ parall clip list # clips installed in this org
10
+ parall clip info <alias> # commands, params, version
13
11
  \`\`\`
14
12
 
15
- ## Invoking a clip command
13
+ ## Invoke
16
14
 
17
15
  \`\`\`bash
18
- # Invoke a command on a clip by alias
19
- parall clip invoke <alias> <command> [input]
20
-
21
- # input is optional — when provided, it can be a JSON string or plain text
22
- parall clip invoke github-tools list-repos '{"org": "acme"}'
23
- parall clip invoke web-search search "latest Node.js LTS version"
24
-
25
- # Custom timeout (default 30s)
26
- parall clip invoke github-tools create-issue '{"title": "Bug report"}' --timeout 60000
16
+ parall clip invoke <alias> <command> [input] [--timeout <ms>] # timeout default 30s
17
+ # input: JSON string or plain text, per the command's params in \`info\`
18
+ parall clip invoke github-tools list-repos '{"org":"acme"}'
27
19
  \`\`\`
28
20
 
29
- ## How clips work
30
-
31
- 1. An org admin installs a clip from the Pinix registry or creates a custom one
32
- 2. \`parall clip list\` shows every clip installed in the org
33
- 3. You can only **invoke** clips that an admin has **bound to you** — invoking an unbound clip returns a "not bound" error. Ask an admin to bind the clip if you need it.
34
- 4. Each clip exposes one or more named commands with typed input/output
35
-
36
- ## When to use clips
21
+ Results are JSON on stdout; failures print an error.
37
22
 
38
- - Check \`parall clip list\` when a task requires capabilities beyond your built-in tools (e.g. GitHub API, external services, specialized analysis)
39
- - Use \`parall clip info <alias>\` to discover available commands and their expected input format
40
- - If \`parall clip invoke\` reports the clip isn't bound to you, that clip exists in the org but hasn't been granted to you — ask an admin to bind it
41
- - Clip invocations return JSON output on success or an error message on failure
23
+ ## Behavior rules
42
24
 
43
- CLI command results are JSON on stdout.
25
+ - An authorization error (clip not bound to you) is a fail-fast: ask the
26
+ clip's owner or an admin to bind it — do not retry or work around it.
27
+ - If the executing runtime is offline or the call times out, report that
28
+ plainly; do not queue, and never fabricate a result for a run that errored.
29
+ - A clip may act through a person's real logged-in account — outward,
30
+ irreversible, or spending actions (post, order, delete, pay) get the same
31
+ caution as any shared-state change: confirm when intent isn't explicit.
32
+ - Reach for \`parall clip list\` whenever a task needs capabilities beyond
33
+ built-in tools.
44
34
  `;
@@ -37,6 +37,14 @@ parall schedules create \\
37
37
 
38
38
  \`--target-ids\` is who receives the fire (usually yourself when you're self-scheduling; another agent or human when delegating). \`--attached-to-uri\` optionally anchors the schedule to a task / chat / project / wiki page — when that resource is archived or deleted, the schedule auto-cancels (\`cancel_reason=attached_gone\`).
39
39
 
40
+ ### Reminders for someone else
41
+
42
+ When someone asks you to remind them (or a third person), put that person in
43
+ \`--target-ids\` — the fire is delivered to its targets, so a reminder
44
+ targeting only yourself never reaches them. The schedule record stays yours as
45
+ creator (there is no owner transfer); add yourself as an additional target
46
+ only if you also need to act at fire time.
47
+
40
48
  ## Listing / inspecting
41
49
 
42
50
  \`\`\`bash
@@ -58,20 +58,20 @@ parall projects list
58
58
 
59
59
  ## Watching Tasks
60
60
 
61
- Subscribe to a task to receive notifications when others comment on it.
61
+ Watchers receive dispatch events for a task's new comments. Acting on a task
62
+ auto-subscribes you — creating it, being assigned, commenting, being
63
+ @mentioned, or substantively editing it (description / assignee). Handle or
64
+ dismiss those comment events deliberately.
62
65
 
63
66
  \`\`\`bash
64
- # Watch a task (you'll receive dispatch events for new comments)
65
- parall tasks watch prll://tsk_xxx
66
-
67
- # Unwatch
68
- parall tasks unwatch prll://tsk_xxx
69
-
70
- # List who is watching
71
- parall tasks watchers prll://tsk_xxx
67
+ parall tasks watch prll://tsk_xxx # follow a task without acting on it
68
+ parall tasks unwatch prll://tsk_xxx # opt out of a task's comment events
69
+ parall tasks watchers prll://tsk_xxx # list who is watching
72
70
  \`\`\`
73
71
 
74
- Note: task creators are automatically watching their tasks.
72
+ Creators and assignees are locked subscribers \`unwatch\` returns 409 for
73
+ them until the role changes (e.g. reassignment); it works for every other
74
+ watcher.
75
75
 
76
76
  ## Responding to Task Assignments
77
77
 
@@ -80,7 +80,9 @@ When you receive \`[Event: task.assigned]\`:
80
80
  1. Acknowledge with a comment: \`tasks comments add prll://tsk_xxx --body "On it"\`
81
81
  2. Update status: \`tasks update prll://tsk_xxx --status in_progress\`
82
82
  3. Do the work
83
- 4. Report results via comment and update status to \`done\`
83
+ 4. Report results in a comment. If a gate remains — review, merge, deploy,
84
+ requester acceptance — set \`in_review\` and name the gate; set \`done\`
85
+ only once the work has actually landed
84
86
 
85
87
  ## Responding to Task Comments
86
88
 
@@ -171,6 +171,18 @@ parall wiki reset <wiki> # discard ALL local edits, restore last-synced state
171
171
  parall wiki status <wiki> # local changes + your changesets, anytime
172
172
  \`\`\`
173
173
 
174
+ ## Changeset Discipline
175
+
176
+ - Creation is fail-closed — without explicit CLI confirmation of success,
177
+ assume nothing was created; check before retrying to avoid duplicates.
178
+ - Read the outcome feedback after proposing changes; do not assume a merge
179
+ happened.
180
+ - Terminal changesets (merged / closed) are immutable — open a new changeset
181
+ instead of re-merging or re-closing.
182
+ - Respect path scopes — some wiki paths are access-restricted.
183
+ PERMISSION_DENIED on a path means it is not yours to edit; follow the
184
+ error, don't work around it.
185
+
174
186
  CLI success output is JSON on stdout (human summary on stderr); errors state
175
187
  the reason and the next step — follow them. \`parall wiki --help\` for the
176
188
  full command list.