@timqi/pier 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +97 -0
- package/dist/agent/config.js +133 -0
- package/dist/agent/credentials.js +179 -0
- package/dist/agent/events.js +253 -0
- package/dist/agent/models.js +15 -0
- package/dist/agent/pi.js +296 -0
- package/dist/boards/boards.js +200 -0
- package/dist/boards/pier.css +445 -0
- package/dist/channels/chains.js +67 -0
- package/dist/channels/chunk.js +28 -0
- package/dist/channels/commands.js +28 -0
- package/dist/channels/config.js +172 -0
- package/dist/channels/control.js +71 -0
- package/dist/channels/conversations.js +65 -0
- package/dist/channels/gatekeeper.js +63 -0
- package/dist/channels/panel.js +233 -0
- package/dist/channels/receipts.js +104 -0
- package/dist/channels/routes.js +110 -0
- package/dist/channels/runtime.js +76 -0
- package/dist/channels/slack-api.js +296 -0
- package/dist/channels/slack-directory.js +77 -0
- package/dist/channels/slack-outbound.js +121 -0
- package/dist/channels/slack-panel.js +122 -0
- package/dist/channels/slack-render.js +214 -0
- package/dist/channels/slack-tool.js +334 -0
- package/dist/channels/slack.js +510 -0
- package/dist/channels/telegram-api.js +78 -0
- package/dist/channels/telegram-panel.js +113 -0
- package/dist/channels/telegram-render.js +96 -0
- package/dist/channels/telegram.js +473 -0
- package/dist/channels/types.js +27 -0
- package/dist/cli.js +101 -0
- package/dist/core/hub.js +53 -0
- package/dist/core/identity.js +66 -0
- package/dist/core/queue.js +11 -0
- package/dist/core/reply.js +202 -0
- package/dist/core/router.js +189 -0
- package/dist/core/types.js +7 -0
- package/dist/db.js +268 -0
- package/dist/log.js +55 -0
- package/dist/main.js +183 -0
- package/dist/paths.js +17 -0
- package/dist/secrets.js +191 -0
- package/dist/service.js +134 -0
- package/dist/settings.js +57 -0
- package/dist/tasks/agent.js +197 -0
- package/dist/tasks/callbacks.js +140 -0
- package/dist/tasks/command.js +74 -0
- package/dist/tasks/definitions.js +316 -0
- package/dist/tasks/execution.js +141 -0
- package/dist/tasks/groups.js +187 -0
- package/dist/tasks/messages.js +248 -0
- package/dist/tasks/routes.js +219 -0
- package/dist/tasks/runs.js +104 -0
- package/dist/tasks/service.js +282 -0
- package/dist/tasks/store.js +168 -0
- package/dist/tasks/tool.js +281 -0
- package/dist/tasks/types.js +5 -0
- package/dist/web/auth.js +280 -0
- package/dist/web/files.js +167 -0
- package/dist/web/public/assets/index-8CinH1uR.css +2 -0
- package/dist/web/public/assets/index-DAgP1Gq8.js +78 -0
- package/dist/web/public/icon-192.png +0 -0
- package/dist/web/public/icon-32.png +0 -0
- package/dist/web/public/icon-512.png +0 -0
- package/dist/web/public/icon-maskable-512.png +0 -0
- package/dist/web/public/icon-touch-192.png +0 -0
- package/dist/web/public/icon.svg +19 -0
- package/dist/web/public/index.html +251 -0
- package/dist/web/public/manifest.webmanifest +16 -0
- package/dist/web/public/sw.js +21 -0
- package/dist/web/server.js +366 -0
- package/dist/web/session-state.js +39 -0
- package/docs/deploy.md +307 -0
- package/package.json +55 -0
- package/skills/pier-boards/SKILL.md +210 -0
- package/skills/pier-slack/SKILL.md +135 -0
- package/skills/pier-tasks/SKILL.md +120 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pier-slack
|
|
3
|
+
description: Read and write Slack through Pier's slack tool — a channel's history for a time range, one thread, posting into a thread, and the Slack-specific syntax for mentions and links. Read before answering questions about Slack conversations or posting anything to a workspace.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Reading and writing Slack
|
|
7
|
+
|
|
8
|
+
Pier holds the bot token and makes every call itself. State what you want; it
|
|
9
|
+
resolves the channel, pages the API and hands back a finished transcript. Reads
|
|
10
|
+
are live and nothing is kept between calls — write down what you need to keep.
|
|
11
|
+
|
|
12
|
+
## Where am I
|
|
13
|
+
|
|
14
|
+
If this conversation reached you *through* Slack, omitting `channel` means
|
|
15
|
+
"here":
|
|
16
|
+
|
|
17
|
+
- `{"operation":"post","text":"..."}` replies in the thread you are in
|
|
18
|
+
- `{"operation":"read_thread"}` reads it
|
|
19
|
+
- `{"operation":"context"}` names it: `channel`, `channelName`, `kind`,
|
|
20
|
+
`threadTs`
|
|
21
|
+
|
|
22
|
+
`inSlack:false` from `context` means a task, subagent or web session started
|
|
23
|
+
this: there is no current conversation and `channel` is required.
|
|
24
|
+
|
|
25
|
+
`{"operation":"channels"}` lists what Pier can reach (`id`, `name`, `kind`,
|
|
26
|
+
`respondsToMessages`); pass either an id or a `#name` anywhere a channel is
|
|
27
|
+
wanted. `not_in_channel` means someone must run `/invite @Pier`.
|
|
28
|
+
|
|
29
|
+
## Never ask for an id
|
|
30
|
+
|
|
31
|
+
You already have them:
|
|
32
|
+
|
|
33
|
+
- **The person talking to you** — a message may start with `[name<id> time]`,
|
|
34
|
+
added by Pier, not typed by them. It appears only when the speaker or the day
|
|
35
|
+
changes, so the last one you saw still applies.
|
|
36
|
+
- **Anyone in a transcript** — every line carries `name[id]`.
|
|
37
|
+
- **This channel and thread** — from `context`.
|
|
38
|
+
|
|
39
|
+
Asking a human to paste their own user ID is never acceptable.
|
|
40
|
+
|
|
41
|
+
## Reading
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{"operation":"read_channel","channel":"#incidents",
|
|
45
|
+
"since":"2024-06-01T00:00:00Z","until":"2024-06-02T00:00:00Z"}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{"operation":"read_thread"}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Omit both arguments for the thread you are in; pass `channel` + `thread_ts` for
|
|
53
|
+
another. A thread read returns the parent plus every reply, with `threadTs` at
|
|
54
|
+
the top of the reply rather than on each line.
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{"operation":"read_message","channel":"#ops","ts":"1717243800.000100"}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
One message and nothing else, when that is the whole question. Add `thread_ts`
|
|
61
|
+
when it was posted inside a thread — a channel read cannot see thread replies,
|
|
62
|
+
and the error will say so.
|
|
63
|
+
|
|
64
|
+
- `since` / `until` / `after` take **ISO 8601, epoch seconds, or a `ts` from an
|
|
65
|
+
earlier read**. Omitting `until` reads up to now.
|
|
66
|
+
- `after` returns only what is strictly newer than that message — use it to
|
|
67
|
+
re-read a channel or thread without seeing what you saw last time.
|
|
68
|
+
- `limit` caps the result (default and max 400). When `truncated` is true,
|
|
69
|
+
narrow the range rather than raising the limit.
|
|
70
|
+
- Messages are oldest-first, one line each, shaped as the reply's `format`
|
|
71
|
+
field says — `<ts> | <time, UTC> | <name>[<id>] | <text>`:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
1717243800.000100 | 2024-06-01T12:10Z | Ada[U1] | deploy? [thread: 4 replies]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The leading `ts` is Slack's id: pass it back as `thread_ts` or `after`.
|
|
78
|
+
- A channel read returns thread **parents** only; `[thread: N replies]` marks
|
|
79
|
+
the ones worth opening with `read_thread`.
|
|
80
|
+
- `incomplete` means the read stopped early and its value says why. Retry or
|
|
81
|
+
work with a partial answer, but do not report it as everything.
|
|
82
|
+
|
|
83
|
+
## Posting
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{"operation":"post","text":"**Deploy done** — 3 services, 0 rollbacks."}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
| Goal | Arguments |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| Reply where you are | omit `channel` and `thread_ts` |
|
|
92
|
+
| Reply in a specific thread | `channel` + `thread_ts` |
|
|
93
|
+
| Start a new top-level message | `thread_ts: "none"` |
|
|
94
|
+
|
|
95
|
+
Going top-level takes the explicit `"none"`: a channel's main flow is wider
|
|
96
|
+
than a thread. A `thread_ts` is never inherited across a change of `channel`.
|
|
97
|
+
The response carries `ts` and `threadTs` for replying under what you posted.
|
|
98
|
+
|
|
99
|
+
## Message syntax
|
|
100
|
+
|
|
101
|
+
`text` is **standard markdown** and Slack renders it natively: `**bold**`,
|
|
102
|
+
`_italic_`, `` `code` ``, fenced blocks, `# headings`, `- lists`, tables and
|
|
103
|
+
blockquotes. Never hand-convert to the older `*bold*` mrkdwn; it renders
|
|
104
|
+
literally.
|
|
105
|
+
|
|
106
|
+
Four things are Slack syntax, which markdown cannot express:
|
|
107
|
+
|
|
108
|
+
| Intent | Write | Not |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| Mention a person | `<@U04B7Q2>` | `@alice` — plain text, no ping |
|
|
111
|
+
| Link a channel | `<#C0123456>` | `#general` — plain text |
|
|
112
|
+
| Notify a group | `<!here>`, `<!channel>` | `@here` — plain text |
|
|
113
|
+
| Hyperlink | `[label](https://…)` | — |
|
|
114
|
+
|
|
115
|
+
- **Never guess an id from a name.** A wrong `<@U…>` either fails or pings a
|
|
116
|
+
stranger, and both look like it worked. With no id, write the person's name
|
|
117
|
+
as prose.
|
|
118
|
+
- **Escape `&`, `<`, `>`** when they are text and not markup: `&`, `<`,
|
|
119
|
+
`>`.
|
|
120
|
+
- Emoji as `:white_check_mark:`, not the raw glyph.
|
|
121
|
+
- ~11,000 characters per message. Split longer content across replies in one
|
|
122
|
+
thread rather than truncating.
|
|
123
|
+
|
|
124
|
+
## Rules
|
|
125
|
+
|
|
126
|
+
- **In a busy thread, say nothing unless you are needed.** You are handed every
|
|
127
|
+
message, including humans talking to each other. `<silent>why</silent>` sends
|
|
128
|
+
nothing at all — prefer it to acknowledging what was not addressed to you.
|
|
129
|
+
- Read before you write. A summary of the wrong thread is worse than none.
|
|
130
|
+
- Never post credentials, tokens or file contents you were not asked to share:
|
|
131
|
+
a channel is usually wider than the conversation you are in.
|
|
132
|
+
- "Slack agent access is switched off" means the operator disabled it on
|
|
133
|
+
purpose. Say so and stop; do not look for another route.
|
|
134
|
+
- Resolve vague times ("yesterday") to an explicit ISO range and say which
|
|
135
|
+
range you used.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pier-tasks
|
|
3
|
+
description: Delegate work to Pier subagents with the task tool — one-shot delegation, core-joined parallel fan-out, chained steps, and mid-run control (steer/resume/contact). Read before delegating to a subagent, coordinating multiple agents, or running long background work.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Orchestrating Pier tasks
|
|
7
|
+
|
|
8
|
+
## Core model
|
|
9
|
+
|
|
10
|
+
- Every run executes a persisted task definition. An inline `task` draft
|
|
11
|
+
(`operation:"run"` without `task_id`) creates and runs a one-shot subagent
|
|
12
|
+
atomically; it is tagged `kind:"subagent"` and hidden from task lists.
|
|
13
|
+
- **Nothing blocks.** Every operation returns immediately; results, group
|
|
14
|
+
joins, and decision replies arrive later as system follow-up messages in
|
|
15
|
+
your session. Your only waiting primitive is ending your turn.
|
|
16
|
+
- The child session survives the run — `resume` continues it with full
|
|
17
|
+
context intact. Poll state without blocking via `{"operation":"get",
|
|
18
|
+
"run_id":"..."}` (or `group_id`, or `task_id` for that task's recent runs).
|
|
19
|
+
|
|
20
|
+
## Single delegation (the common case)
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{"operation":"run","task":{"name":"review-auth","action":{
|
|
24
|
+
"type":"agent","session":{"mode":"fresh","cwd":"/abs/project"},
|
|
25
|
+
"prompt":"Review src/auth/*.ts for injection risks. Output: file:line + issue + fix."}}}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Returns a run summary (`runId`, `state:"queued"`, ids). Finish your turn; the
|
|
29
|
+
result arrives as a follow-up. `callback:"none"` silences it.
|
|
30
|
+
|
|
31
|
+
A summary's `triggerSource` is who fired that run (`agent` when you did, plus
|
|
32
|
+
`manual` / `cron` / `watch` / `task`); a definition's `trigger` is only its
|
|
33
|
+
schedule policy, where `manual` means on-demand — by a human or by you.
|
|
34
|
+
|
|
35
|
+
- `fresh`: clean context, requires `cwd`. `fork`: child starts with a copy of
|
|
36
|
+
your conversation — use when the task needs your context. `reuse`: sends
|
|
37
|
+
work to an existing session by id.
|
|
38
|
+
- The child inherits your current model unless `launch.model` is set.
|
|
39
|
+
Unknown models fail with the available list in the error. `launch` applies to
|
|
40
|
+
`fresh` and `fork` only — a `reuse` session owns its own model and tools.
|
|
41
|
+
- The child has the same tools you do; there is no capability knob to pick.
|
|
42
|
+
- Runs time out after 900s by default; set `timeoutSeconds` in the draft for
|
|
43
|
+
longer jobs.
|
|
44
|
+
|
|
45
|
+
## Parallel fan-out (core-joined)
|
|
46
|
+
|
|
47
|
+
Pass `tasks[]` (each entry a draft or `{"task_id":"..."}`) and Pier joins the
|
|
48
|
+
group in core — you never track run ids across turns:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{"operation":"run","join":"all","tasks":[
|
|
52
|
+
{"name":"review-correctness","action":{...}},
|
|
53
|
+
{"name":"review-tests","action":{...}}]}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- `join:"all"` (default): one aggregated follow-up when every member
|
|
57
|
+
finishes, listing each member's name, state, and result.
|
|
58
|
+
- `join:"first"`: the first finished run wins; the rest are cancelled but
|
|
59
|
+
their sessions stay resumable (ids are in the callback).
|
|
60
|
+
- `get`/`cancel` accept `group_id`: observe or stop the whole group as one
|
|
61
|
+
unit.
|
|
62
|
+
- Limits: 4 agents active at once, 16 children per tree, nesting caps at
|
|
63
|
+
you → child → grandchild. Extra members queue rather than fail.
|
|
64
|
+
|
|
65
|
+
## Chains
|
|
66
|
+
|
|
67
|
+
Run step 1, end your turn, receive its callback, splice the needed part into
|
|
68
|
+
step 2's prompt. Children share nothing implicitly (except fork's copied
|
|
69
|
+
history) — every prompt must be self-contained: paths, acceptance criteria,
|
|
70
|
+
expected output format. Branching and retries are your own logic between
|
|
71
|
+
turns.
|
|
72
|
+
|
|
73
|
+
## Choosing a model
|
|
74
|
+
|
|
75
|
+
Omit `launch.model` to inherit your own model — the right default. Override
|
|
76
|
+
only when the task profile clearly differs:
|
|
77
|
+
|
|
78
|
+
- `anthropic/claude-opus-5` — hardest reasoning: architecture, gnarly debugging
|
|
79
|
+
- `anthropic/claude-fable-5` — long autonomous implementation runs
|
|
80
|
+
- `anthropic/claude-sonnet-5` — balanced default: implementation, review
|
|
81
|
+
- `anthropic/claude-haiku-5` — cheap and fast: listings, extraction, simple checks
|
|
82
|
+
- `openai/gpt-5.6` series (e.g. `gpt-5.6-sol`) — cross-vendor second opinion
|
|
83
|
+
|
|
84
|
+
An unknown id fails with the available models listed in the error.
|
|
85
|
+
|
|
86
|
+
## Mid-run control
|
|
87
|
+
|
|
88
|
+
- `steer` — interrupt a running child with corrected instructions
|
|
89
|
+
- `follow_up` — queue a message for after its current turn
|
|
90
|
+
- `resume` — continue a finished child in its same session; this expires any
|
|
91
|
+
unanswered decision on that run
|
|
92
|
+
- `cancel` — stop a run (or a whole group via `group_id`); cancellation
|
|
93
|
+
cascades to the run's own children
|
|
94
|
+
|
|
95
|
+
## Supervisor decisions (as a child)
|
|
96
|
+
|
|
97
|
+
`{"operation":"contact","reason":"decision","message":"..."}` returns a
|
|
98
|
+
receipt immediately. State what you are waiting for and **end your turn** —
|
|
99
|
+
never spin or poll. The answer arrives as a follow-up if your run is still
|
|
100
|
+
active; if your run already finished, Pier resumes your session with the
|
|
101
|
+
reply as the prompt. One open decision per run.
|
|
102
|
+
|
|
103
|
+
As a parent: the question arrives as a system input with a message id, steered
|
|
104
|
+
into your current turn at the next step boundary so a blocked child is not
|
|
105
|
+
waiting on the end of your turn; answer
|
|
106
|
+
with `{"operation":"reply","message_id":"...","message":"..."}`. A run that
|
|
107
|
+
finished while awaiting your answer shows `pendingDecisionId` in `get` and
|
|
108
|
+
sends no completion callback — the question is the notification.
|
|
109
|
+
|
|
110
|
+
`reason:"progress"` is fire-and-forget status for the parent.
|
|
111
|
+
|
|
112
|
+
## Rules
|
|
113
|
+
|
|
114
|
+
- One concern per child. For fan-out, let core join via `tasks[]` — never
|
|
115
|
+
hand-aggregate run ids across turns.
|
|
116
|
+
- Repeating the same role? Create a durable task once (`operation:"create"`)
|
|
117
|
+
and run it by `task_id` — cheaper than re-sending the draft every time.
|
|
118
|
+
- Inline drafts must use `action.type:"agent"`; triggers are forced manual;
|
|
119
|
+
do not target another session with `reuse` from an inline draft.
|
|
120
|
+
- After launching work, end your turn. The callback starts your next one.
|