@parall/parall 1.20.1 → 1.21.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.
@@ -4,7 +4,8 @@
4
4
  "skills": [
5
5
  "./skills/parall-wiki",
6
6
  "./skills/parall-tasks",
7
- "./skills/parall-platform"
7
+ "./skills/parall-platform",
8
+ "./skills/parall-schedules"
8
9
  ],
9
10
  "configSchema": {
10
11
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/parall",
3
- "version": "1.20.1",
3
+ "version": "1.21.0",
4
4
  "description": "OpenClaw channel plugin for Parall IM",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,8 +15,8 @@
15
15
  "openclaw.plugin.json"
16
16
  ],
17
17
  "dependencies": {
18
- "@parall/agent-core": "1.20.1",
19
- "@parall/sdk": "1.20.1"
18
+ "@parall/agent-core": "1.21.0",
19
+ "@parall/sdk": "1.21.0"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/node": "^22.0.0",
@@ -75,4 +75,22 @@ npx --yes @parall/cli@latest dm "Alice" --file /tmp/report.pdf --text "Report at
75
75
 
76
76
  `--file` and `--attachment` are mutually exclusive. `--text` can be combined with either.
77
77
 
78
+ ## Reference URIs
79
+
80
+ Every entity is addressable with a `prll://` URI. Common prefixes you'll see in events, messages, and schedule descriptions:
81
+
82
+ | Prefix | Entity | Skill |
83
+ |--------|--------|-------|
84
+ | `prll://usr_` | User (human or agent) | parall-platform |
85
+ | `prll://cht_` | Chat | parall-platform |
86
+ | `prll://msg_` | Message | parall-platform |
87
+ | `prll://tsk_` | Task | parall-tasks |
88
+ | `prll://prj_` | Project | parall-tasks |
89
+ | `prll://sch_` | Schedule (time trigger) | parall-schedules |
90
+ | `prll://srn_` | Schedule run (single fire audit record; carries fire-time snapshot) | parall-schedules |
91
+ | `prll://wik_` | Wiki | parall-wiki |
92
+ | `prll://att_` | Attachment | parall-platform (files) |
93
+
94
+ When a message or event references `prll://sch_xxx` or `prll://srn_xxx`, or when you receive `[Event: schedule.fired]`, switch to the **parall-schedules** skill for the CLI commands (create / list / pause / resume / cancel / runs).
95
+
78
96
  All CLI output is JSON.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: parall-schedules
3
+ description: "Parall schedule operations: create / pause / resume / cancel recurring or one-shot time triggers; respond to schedule fire events. Use when: user asks to set up a recurring reminder, schedule a delayed prompt, run cron-like work, or when the agent receives an `[Event: schedule.fired]` dispatch."
4
+ ---
5
+
6
+ # Parall Schedules
7
+
8
+ A **Schedule** is a platform time trigger. At fire time the platform delivers the schedule's `description` to a target — 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.
9
+
10
+ Three spec types — pick exactly one:
11
+
12
+ - `cron` — 5-field expression (min granularity: 1 minute)
13
+ - `interval` — every N seconds (minimum 60)
14
+ - `one_shot` — fire once at a specific time
15
+
16
+ ## Creating schedules
17
+
18
+ ```bash
19
+ # Recurring cron (weekdays 10am New York)
20
+ npx --yes @parall/cli@latest schedules create \
21
+ --name "Daily standup" \
22
+ --description "Ask the team for their plan today; see prll://wik_xxx for the standup template" \
23
+ --target-id prll://usr_xxx \
24
+ --cron-expr "0 10 * * 1-5" \
25
+ --timezone America/New_York \
26
+ --attached-to-uri prll://cht_xxx
27
+
28
+ # Every 30 minutes
29
+ npx --yes @parall/cli@latest schedules create \
30
+ --name "CI watch" \
31
+ --description "Check the deploy status and flag failures" \
32
+ --target-id prll://usr_xxx \
33
+ --interval-seconds 1800
34
+
35
+ # One-shot at a future RFC3339 time
36
+ npx --yes @parall/cli@latest schedules create \
37
+ --name "Followup" \
38
+ --description "Remind the user about the PR review if still pending" \
39
+ --target-id prll://usr_xxx \
40
+ --run-at 2026-04-19T15:00:00Z
41
+ ```
42
+
43
+ `--target-id` 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`).
44
+
45
+ ## Listing / inspecting
46
+
47
+ ```bash
48
+ npx --yes @parall/cli@latest schedules list --status active,paused
49
+ npx --yes @parall/cli@latest schedules list --attached-to prll://tsk_xxx
50
+ npx --yes @parall/cli@latest schedules list --target-id prll://usr_xxx
51
+ npx --yes @parall/cli@latest schedules get prll://sch_xxx
52
+ npx --yes @parall/cli@latest schedules runs prll://sch_xxx # fire history
53
+ npx --yes @parall/cli@latest schedules run prll://srn_xxx # single run incl. fire-time snapshot
54
+ ```
55
+
56
+ ## Lifecycle
57
+
58
+ ```bash
59
+ npx --yes @parall/cli@latest schedules update prll://sch_xxx --description "New prompt"
60
+ npx --yes @parall/cli@latest schedules pause prll://sch_xxx # reversible
61
+ npx --yes @parall/cli@latest schedules resume prll://sch_xxx # does NOT catch up missed slots
62
+ npx --yes @parall/cli@latest schedules cancel prll://sch_xxx # terminal; row + runs preserved, prll://sch_ ref stays valid
63
+ npx --yes @parall/cli@latest 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) — cancel it and leave the audit trail. Delete is for never-fired test/accidental schedules only.
64
+ ```
65
+
66
+ `spec_type` cannot be changed via update — if you need to switch between cron / interval / one_shot, cancel the old one and create a new schedule.
67
+
68
+ ## Responding to schedule fires
69
+
70
+ When you receive `[Event: schedule.fired]`, the platform has fired a schedule targeting you.
71
+
72
+ The runtime (agent-core) has already done the heavy lifting: it fetched the schedule run and inlined the fire-time `description` (a frozen snapshot — 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 — the description is already in the prompt body.
73
+
74
+ Your job is to interpret the description and act:
75
+
76
+ 1. Read the description and any `prll://` refs it contains
77
+ 2. Do whatever the prompt asks (send a message, create a task, update a wiki, etc.) — there is no canonical response format
78
+ 3. 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
79
+
80
+ Do not treat schedule fires as "tasks assigned to you" — 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.
81
+
82
+ **Fetching the run explicitly** (optional): `schedules run prll://srn_xxx` returns the same snapshot plus `dispatch_event_id` / `inbox_item_id` 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 — don't retry.
83
+
84
+ CLI command results are JSON on stdout; mutation commands may emit auxiliary hints on stderr (for example, `Created: prll://sch_xxx`).
package/src/hooks.ts CHANGED
@@ -3,6 +3,18 @@ import { PRLL_BEHAVIOR, PRLL_IDENTITY, PRLL_REFERENCE_GUIDE } from "@parall/agen
3
3
  import { extractAccountIdFromSessionKey } from "./session.js";
4
4
  import { clearDispatchGroupKey, getDispatchGroupKey, getDispatchMessageId, getParallAccountState, getSessionChatId } from "./runtime.js";
5
5
 
6
+ /**
7
+ * Map the session's stored target ID (whatever the current dispatch routed
8
+ * to — chat, task, or schedule) to the `target_type` field on agent_step.
9
+ * Keeps tool_call / tool_result attribution correct across event types.
10
+ */
11
+ function stepTargetType(targetId: string): string {
12
+ if (targetId.startsWith("cht_")) return "chat";
13
+ if (targetId.startsWith("tsk_")) return "task";
14
+ if (targetId.startsWith("sch_")) return "schedule";
15
+ return "";
16
+ }
17
+
6
18
  /**
7
19
  * Resolve the ParallClient + orgId + sessionId for a hook context.
8
20
  * Returns undefined if the account/session is not active.
@@ -22,13 +34,19 @@ function resolveClientForHook(sessionKey: string | undefined) {
22
34
 
23
35
  const PRLL_CHANNEL_CONTEXT = `## Parall Channel — Message Delivery
24
36
 
25
- Messages from the Parall channel arrive as \`[Event: ...]\` blocks.
37
+ Events from the Parall channel arrive as \`[Event: ...]\` blocks.
26
38
  Your text output is **not delivered to the user** — it is discarded silently.
27
- To reply, you **must** use the Parall CLI via the exec (Bash) tool.
39
+ To respond, you **must** use the Parall CLI via the exec (Bash) tool.
40
+
41
+ ### Event types and where to reply
28
42
 
29
- Each event includes \`[Chat: ... (prll://cht_xxx)]\` use that chat ID (or full URI) to reply:
43
+ - **\`[Event: message.new]\`** — includes \`[Chat: ... (prll://cht_xxx)]\`. Reply into that chat:
30
44
 
31
- npx --yes @parall/cli@latest messages send prll://cht_xxx --text "Your reply here"
45
+ npx --yes @parall/cli@latest messages send prll://cht_xxx --text "Your reply here"
46
+
47
+ - **\`[Event: task.assigned]\` / \`[Event: task.comment.created]\`** — includes \`[Task: ... (prll://tsk_xxx)]\`. Act on the task; use task CLI subcommands (\`tasks update\`, \`tasks comment\`). See the \`parall-tasks\` skill.
48
+
49
+ - **\`[Event: schedule.fired]\`** — includes \`[Schedule: prll://sch_xxx]\` + \`[Run: prll://srn_xxx]\` + optional \`[Attached: prll://...]\`. The body is the fire-time \`description\` verbatim. It is an opaque trigger — decide what to do (reply into an attached chat, create a task, update a wiki file, or do nothing) based on the description. The CLI does not have a "reply to schedule" primitive; any follow-up goes through the appropriate target (chat / task / wiki).
32
50
 
33
51
  Credentials are pre-configured in every Bash command — no setup needed.
34
52
  Load the \`parall-platform\` skill for full CLI reference.
@@ -66,7 +84,7 @@ export function registerParallHooks(api: OpenClawPluginApi) {
66
84
  try {
67
85
  const step = await resolved.client.createAgentStep(resolved.orgId, resolved.agentUserId, resolved.sessionId, {
68
86
  step_type: "tool_call",
69
- target_type: resolved.chatId.startsWith("cht_") ? "chat" : resolved.chatId.startsWith("tsk_") ? "task" : "",
87
+ target_type: stepTargetType(resolved.chatId),
70
88
  target_id: resolved.chatId || undefined,
71
89
  content: {
72
90
  call_id: event.toolCallId,
@@ -102,7 +120,22 @@ export function registerParallHooks(api: OpenClawPluginApi) {
102
120
  injectedEnv.PRLL_AGENT_ID = state.agentUserId;
103
121
  if (state.activeSessionId) injectedEnv.PRLL_SESSION_ID = state.activeSessionId;
104
122
  if (stepId) injectedEnv.PRLL_STEP_ID = stepId;
105
- if (chatId) injectedEnv.PRLL_CHAT_ID = chatId;
123
+ if (chatId) {
124
+ if (chatId.startsWith("sch_")) {
125
+ // Schedule-triggered dispatch: expose PRLL_SCHEDULE_ID so the agent
126
+ // can resolve the schedule; deliberately do NOT set PRLL_CHAT_ID,
127
+ // because schedule events have no chat to reply into, and leaving
128
+ // chatId=sch_* would mislead scripts into `messages send
129
+ // prll://sch_*` (a non-existent CLI path). The run snapshot is
130
+ // available via PRLL_TRIGGER_MESSAGE_ID (srn_*) for agents that
131
+ // want to re-fetch fire-time content.
132
+ injectedEnv.PRLL_SCHEDULE_ID = chatId;
133
+ } else {
134
+ // Chat and task dispatches continue to populate PRLL_CHAT_ID for
135
+ // backward compatibility with existing agent scripts.
136
+ injectedEnv.PRLL_CHAT_ID = chatId;
137
+ }
138
+ }
106
139
  if (triggerMsgId) injectedEnv.PRLL_TRIGGER_MESSAGE_ID = triggerMsgId;
107
140
  if (state.wikiMountRoot) injectedEnv.PRLL_WIKI_MOUNT_ROOT = state.wikiMountRoot;
108
141
 
@@ -127,7 +160,7 @@ export function registerParallHooks(api: OpenClawPluginApi) {
127
160
  try {
128
161
  await resolved.client.createAgentStep(resolved.orgId, resolved.agentUserId, resolved.sessionId, {
129
162
  step_type: "tool_result",
130
- target_type: resolved.chatId.startsWith("cht_") ? "chat" : resolved.chatId.startsWith("tsk_") ? "task" : "",
163
+ target_type: stepTargetType(resolved.chatId),
131
164
  target_id: resolved.chatId || undefined,
132
165
  content: {
133
166
  call_id: event.toolCallId,