eve-hub 0.16.34 → 0.16.36
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/onboarding/SKILL.md +158 -50
- package/onboarding/check-report.mjs +189 -21
- package/onboarding/files.gen.mjs +1 -1
- package/onboarding/github-facts.mjs +33 -2
- package/package.json +1 -1
- package/skills/onboarding-profile.gen.mjs +1 -1
- package/tools/onboarding_scripts.js +1 -1
- package/tools/post_message.js +2 -2
- package/tools/update_thread.js +2 -2
package/onboarding/SKILL.md
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: onboarding-profile
|
|
3
|
-
description: "Right after sign-in: ask for the Kit access you need,
|
|
3
|
+
description: "Right after sign-in: ask for the Kit access you need, fan out over their Slack, Notion, GitHub and LLM usage, then write a short cited read of how they work, propose the bot team that fits them for them to pick from, and draft schedules that keep them on track. Reads only; the one write is a pull request the user approves by merging."
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Profile the user from Slack, Notion, GitHub and their LLM usage
|
|
8
8
|
|
|
9
|
-
The profile is built from many small reads run at the same time, not one pass. You gather the raw facts (step 1), split them into slices that each read one source or one piece of a source (
|
|
9
|
+
The profile is built from many small reads run at the same time, not one pass. You gather the raw facts (step 1), split them into slices that each read one source or one piece of a source (steps 2 and 3, wave 1), merge the slices into three areas (step 4, wave 2), and then turn the areas into a read of the user in three passes: a read pass, a critique pass and a write pass (step 5). Every claim cites a URL or `fact:` reference that is in the facts, and everything you could not read is said, never guessed.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The result is two files. `read.md` is about one page on how the user works and the team that fits them. `facts.md` is the appendix it cites: the ten questions below, answered from the facts.
|
|
12
|
+
|
|
13
|
+
Nothing is posted to Slack and nothing is committed by the run itself; its own writes are the pull request in step 6, which the user approves by merging, and a wake-up in this thread for any need that runs once (step 5c), and the first task (below) pushes only once the user says `go` in its thread. The user sees the first message about 20 seconds in, naming the first task, when there is one, that is already being worked on, one message with every Kit approve link if access is pending (step 1), up to four two-sentence findings as the slices finish, one `ask` to confirm what the facts say they would hand off, your answers to anything they ask, and at the end one message with the read, their team and the schedules, followed by one `ask` to pick team changes (step 7). If a step cannot finish, the final message says which and what the user must do; never write the read as if every source had been read.
|
|
12
14
|
|
|
13
15
|
The whole run is capped at 25 minutes. Every directory below is under `/tmp/onboarding-skill/`.
|
|
14
16
|
|
|
15
|
-
##
|
|
17
|
+
## `facts.md` answers these ten questions
|
|
16
18
|
|
|
17
19
|
Each gets an answer with a citation or a "Could not tell" line saying what was missing.
|
|
18
20
|
|
|
@@ -27,11 +29,31 @@ Each gets an answer with a citation or a "Could not tell" line saying what was m
|
|
|
27
29
|
9. Which models and coding agents they use, how much, and when.
|
|
28
30
|
10. How much of their shipped work is agent-assisted.
|
|
29
31
|
|
|
30
|
-
Plus
|
|
32
|
+
Plus four more: what they shipped and own, what people tag them for, what they missed (unanswered mentions, requested reviews, stale or conflicted PRs), and which open work-streams to close or focus on.
|
|
33
|
+
|
|
34
|
+
## `read.md` is the core read of the user
|
|
35
|
+
|
|
36
|
+
About one page, with these five sections in this order:
|
|
37
|
+
|
|
38
|
+
1. `## Who you are`: two sentences. Their role in their own terms, and the one thing to act on first.
|
|
39
|
+
2. `## How you work`: 4 to 6 traits. A trait is a claim about behavior, not a count. Each is a `###` heading naming the trait, then the claim in one sentence, then at least two `-` evidence items from at least two different sources (Slack, GitHub, Notion, v0, the Mac's usage files, the user's answers), each citing as `facts.md` does, then an `Against:` line (what would contradict it, and whether the facts show that) and a `Drives:` line (the decision it drives for the team or the schedules).
|
|
40
|
+
3. `## Where your time and risk go`: where the hours go compared with what leadership says matters, and what is drifting (stale stacks, review debt, areas only they own).
|
|
41
|
+
4. `## Your team`: one table row per change to the current roster (keep, add, change or remove), each naming the trait behind it.
|
|
42
|
+
5. `## Act on first`: three items, each citing a URL from the facts; when the run has a first task, the first item is that task, with its thread linked.
|
|
43
|
+
|
|
44
|
+
The traits come from these dimensions. They are a prompt for where to look, not a formula:
|
|
45
|
+
|
|
46
|
+
- How they use agents: how much they delegate, how many run in parallel, how often subagents run, and how closely they review what comes back.
|
|
47
|
+
- Author or reviewer: who depends on them and who they depend on.
|
|
48
|
+
- Rhythm: their working hours, bursts, and when agents run without them.
|
|
49
|
+
- Spread: how many programs and repos they hold at once, and whether those form one program.
|
|
50
|
+
- Closure: whether work gets finished or piles up as drafts, conflicts and review requests.
|
|
51
|
+
|
|
52
|
+
The user's own pick from the handoff `ask` (`fact:interview/handoff`) counts as one source. A trait resting on their pick alone fails the checker. Where their pick and the data disagree (they say review is what they'd keep, against 206 reviews for 1,412 PRs opened), the trait says so plainly, because that gap is often the most useful line in the read.
|
|
31
53
|
|
|
32
54
|
## Subagents do the work, and you talk with the user
|
|
33
55
|
|
|
34
|
-
Every collection and synthesis task runs as a subagent: the Slack base facts, every slice, every area and the
|
|
56
|
+
Every collection and synthesis task runs as a subagent: the Slack base facts, every slice, every area and each pass of the read. You run none of the collection scripts yourself, so you stay free to talk with the user the whole time.
|
|
35
57
|
|
|
36
58
|
You do only what a subagent can't or shouldn't:
|
|
37
59
|
|
|
@@ -41,25 +63,48 @@ You do only what a subagent can't or shouldn't:
|
|
|
41
63
|
- planning the slices (step 2), writing each reader's report to its file, and running `check-report.mjs`;
|
|
42
64
|
- the pull request (step 6) and every post.
|
|
43
65
|
|
|
44
|
-
###
|
|
66
|
+
### Post to the user while the subagents read
|
|
67
|
+
|
|
68
|
+
The full read takes about nine minutes, so the user gets something to act on first. Before step 7 you post only these: the first message (step 1), the access post of step 1 if access is pending, the findings ("Post a finding as each group of slices is checked", below), the handoff `ask` ("Confirm what they would hand off", below), and your answers to anything they ask.
|
|
69
|
+
|
|
70
|
+
Never ask the user free-text questions about how they work: nobody types answers during a run. What they own and how a day goes come from the `role` and `work` areas; what a bot never does without asking is set by the workspace's standing decisions, so it needs no question. The one thing the facts can only suggest, what they would hand off first, you infer and they confirm with one tap.
|
|
71
|
+
|
|
72
|
+
Never post progress ("eleven more subagents started"), a tour of the team, or a trait or judgment before step 7, except the handoff `ask`: before then a post holds only facts the checker has passed, because the critique (5b) is what tests a judgment, and the `ask` is a guess the user settles.
|
|
73
|
+
|
|
74
|
+
### The first message and the first task
|
|
75
|
+
|
|
76
|
+
The first message comes from `facts/github/quick.json` alone (step 1), in about 20 seconds, so it holds GitHub counts and links and nothing from Slack. One bubble of at most three sentences, written the way a colleague would say it: what you are reading (their Slack, Notion, GitHub and v0, and their Mac's coding-agent usage if a Mac bot is on the team) and that the full read lands in about nine minutes; then the first task as a plan, with its link, the outcome and a short why, and the link to its thread. For example: "To kick us off, let's grab [eve#5300](https://github.com/vercel/eve/pull/5300) and get it merged. It's already approved and looks mergeable, so the failing checks are all that's left. Let's do that [in this thread](thr_…)." The why is a plain clause about the item, never the selection rule, a ranking ("the smallest of your approved open PRs") or line counts. Say only what is true of the item: "it's already approved" for the user's own approved PR, never "you approved it".
|
|
45
77
|
|
|
46
|
-
|
|
78
|
+
Pick the first task yourself from `quick.json`, as a judgment with a one-line reason, not a score: one item that is small, can be finished in one thread, and is closest to landing. Look in this order: the user's approved PRs (`approved`) whose `checks` fail or that are `CONFLICTING`; their PRs with changes requested (`changesRequested`); the oldest review requests (`reviewRequested`); their assigned issues (`assignedIssues`). A candidate's state is the one `quick.json` holds for it at this run, never one remembered from an earlier run or another thread. With no candidate, the first message says so and names no task; never invent one.
|
|
47
79
|
|
|
48
|
-
|
|
49
|
-
2. How a piece of work moves: they ask, the coordinator routes it, the planner posts a brief, they say yes, the builder opens a PR, the reviewer gives a verdict, and they approve the merge. Load the forms skill and draw it as a `flow`.
|
|
50
|
-
3. What waits on them: the yes on a brief, merge approval, and anything that needs their eyes. Everything else, a bot does.
|
|
51
|
-
4. How to talk to the team: one thread per piece of work, and an @-mention of the bot that should act next.
|
|
52
|
-
5. Two or three standing decisions in effect, each in one sentence on what it means for them.
|
|
80
|
+
Before opening a thread, run `list_threads` with `archived: include` and the PR or issue URL as `query`, then again with its `owner/repo#number`. An item an active thread already works on is already moving, so prefer a candidate no active thread holds. If you still pick one an active thread owns, use that thread: post the task there to its owner, the bot that posted its brief or build, and never instruct its builder yourself, because two bots instructing one builder undo each other's work. An archived thread takes no posts, so for an item only an archived thread mentions, open a new thread and link the archived one in the handoff. Otherwise open one thread for the task and hand it over in a post there before the first message goes out: to the builder for the user's own PR or an issue, to the reviewer for a review request. That post opens with one line to the user saying who is on it and what it does, for example "Ok. I've put @builder on this. It'll find why the checks fail and prepare the fix, and pushes nothing until you say `go`." The run assigns a bot that is already on the team and never says it created one. The handoff names the PR or issue URL and says what it may do before the user answers. The builder reads the failing check logs or the conflict, finds the cause and prepares the fix on a local branch, then posts the cause and the diff, and pushes nothing until the user says `go` in that thread, because a push to an approved PR is seen by its reviewers and can dismiss the approval. The reviewer posts a draft review in the thread and sends nothing to GitHub until the user says `go`. Merging waits on the user as for any PR. The task's thread is linked again from `## Act on first` (5a).
|
|
53
81
|
|
|
54
|
-
|
|
82
|
+
Before writing the first message, check every number, date and name in the message against the exact field in `quick.json` it comes from: a count is `total`, not `listed` (`listed` is only the page that was read); a date is the item's own `createdAt` or `updatedAt`; a search named in `unreadable` was not read, so it is never a zero. `check-report.mjs` only checks that each link is in the facts, not that the sentence states its value right, so this check is yours.
|
|
55
83
|
|
|
56
|
-
|
|
57
|
-
- Each is one bubble, at most 700 characters, and follows your writing rules.
|
|
58
|
-
- Name bots in plain text. Never @-mention one: a mention wakes that bot.
|
|
59
|
-
- Say nothing about the profile's findings: those come in step 7.
|
|
60
|
-
- Stop once the profile subagent of step 5 returns. At most five messages in all.
|
|
84
|
+
Write the first message to `/tmp/onboarding-skill/first.md`, run `node check-report.mjs --profile first.md --facts facts` in `/tmp/onboarding-skill`, fix what it prints, and post it.
|
|
61
85
|
|
|
62
|
-
|
|
86
|
+
### Post a finding as each group of slices is checked
|
|
87
|
+
|
|
88
|
+
When every slice of a group below is written and passes the checker, post one finding for it, at most four in the run, in the order they come in:
|
|
89
|
+
|
|
90
|
+
1. GitHub: `reviews`, the `repo-*` slices and `calendar`.
|
|
91
|
+
2. LLM: `agent-assisted`, and `facts/local/` if the Mac's files are in.
|
|
92
|
+
3. Slack: `mentions` and the `own-*` slices.
|
|
93
|
+
4. Team: the `team-*` slices, `leadership` and `notion`.
|
|
94
|
+
|
|
95
|
+
A finding is one `- ` list item of two sentences, written to `findings/<n>.md`. The first holds one count or fact copied from the group's slices, with the URL or `fact:` reference it rests on, and why it matters to the user. The second is the next step, what the team or the user does about it, linking the item, channel or thread it acts on. For example: "103 of 237 Slack mentions in 30 days have no reply from you, and 9 of the 20 listed are in [inc-8535](https://vercel.slack.com/archives/C0AJ0C32XPB/p1794014521602859?thread_ts=1794014424.527769), so V questions still land on you while Philipp takes V over. I can list those 9 threads for Philipp so he answers them in [inc-8535](https://vercel.slack.com/archives/C0AJ0C32XPB) instead." A count with no reason or next step is not a finding. Check it with `node check-report.mjs --finding findings/<n>.md --facts facts` before it posts: the checker fails anything but one item of two sentences that each cite a fact; whether the reason and the step are good is yours to judge. Check its count, date and names against the exact fields of the slice it comes from first, as for the first message: `total` against `listed`, the item's own dates, and `unreadable`. Pick the fact the user would act on ("91 review requests in vercel/eve are waiting on you"), never a trait or a judgment, and never one already in the first message. A group whose slices found nothing worth a line posts nothing.
|
|
96
|
+
|
|
97
|
+
### Confirm what they would hand off
|
|
98
|
+
|
|
99
|
+
When the `role` and `work` areas both pass the checker, infer from them what the user would hand off first, and post one `ask`. The question is the inference with the facts behind it, ending "Right?", for example "You'd hand off review chasing and Slack follow-ups first, since 240 reviews wait on you and 103 mentions have no reply. Right?" The options are "Yes, start there", then up to three other readings the areas support, each with a `line` naming its fact, then "None of these". Labels are at most 40 characters. This is the run's only `ask` before step 7.
|
|
100
|
+
|
|
101
|
+
When you post the `ask`, write `/tmp/onboarding-skill/facts/handoff-ask.md` with the question as posted and every option's label and `line`. As soon as they answer, append their answer to `/tmp/onboarding-skill/facts/interview.md` under `## handoff`, as three parts: `Asked:` the question word for word, `Offered:` each option's label and `line`, and `Picked:` the label they tapped, or their typed reply word for word. The read cites it as `fact:interview/handoff`, so whoever reads that fact sees what was inferred, what else was offered, and what they confirmed. A pick of "None of these" is a fact too: the inference was wrong. Until they answer, the read states the inference as unconfirmed, citing the facts behind it, not `fact:interview/handoff`.
|
|
102
|
+
|
|
103
|
+
When you wait, use `eve__task_wait`: it returns on a task result or on a new message from the user. If the user asks something, answer it in the thread right away, then wait again. If they ask for work, route it as you normally would; the onboarding run goes on. Never wait for their tap: the read uses whatever has arrived when it starts, and a tap that arrives after the read pass started goes to it as "Evidence that arrives late" (step 5) says.
|
|
104
|
+
|
|
105
|
+
### Log when each step ends
|
|
106
|
+
|
|
107
|
+
The run's length is judged against the time each step took, so log it. `onboarding_scripts` starts a fresh `/tmp/onboarding-skill/`, so right after it returns, run `echo "start $(date -u +%T)" > /tmp/onboarding-skill/phases.log`. When each of these ends, append one line the same way: `quick` (`gh onboarding-facts --quick` returned), `first` (the first message posted), `facts` (the full `gh onboarding-facts` returned), `finding1` to `finding4` (each finding posted, numbered in the order they post), `slices` (every wave 1 report is written and checked), `areas` (every wave 2 area is checked), `read` (5a returned), `critique` (5b returned), `write` (5c's checker prints nothing), `pr` (step 6's checks finished: the PR URL and `pass` or `fail`, or `pr none` when the workspace has no repo), `post` (step 7 posted). Step 7 never posts before the `pr` line is written. After step 7, run `node check-report.mjs --phases phases.log`: it prints any step that is missing, repeated or out of order. Keep `phases.log` with `read.md`.
|
|
63
108
|
|
|
64
109
|
## 0. Hand the Mac half to the bot on the Mac
|
|
65
110
|
|
|
@@ -67,7 +112,7 @@ You run on Vercel and can't see the user's Mac. If `list_agents` shows a bot tha
|
|
|
67
112
|
|
|
68
113
|
Its LLM-usage post links one facts file per coding agent, written by `agent-usage-facts.mjs --usage-only`: names and counts, with no web permalinks. When it arrives, fetch each linked file with `fetch_upload` into `/tmp/onboarding-skill/facts/local/usage-<source>.json` (`claude-code`, `codex`, `opencode`, `cursor`). These files, not the post's table, are what the profile cites, with `fact:` references (step 5).
|
|
69
114
|
|
|
70
|
-
If the files arrive after the `llm` synthesizer of step 4 has started, its area did not read them
|
|
115
|
+
If the files arrive after the `llm` synthesizer of step 4 has started, its area did not read them. Fetch them into `facts/local/`, start one `agent` copy as the `llm` synthesizer on them alone, and check its `areas/llm-local.md` with `node check-report.mjs --profile areas/llm-local.md --facts facts`. Then hand `areas/llm-local.md` on as "Evidence that arrives late" (step 5) says.
|
|
71
116
|
|
|
72
117
|
With no bot that runs `local`, skip this step and say nothing about a Mac; question 9 then rests on v0 alone, and "Could not tell" says the Mac's agent logs were not read.
|
|
73
118
|
|
|
@@ -80,13 +125,17 @@ Make all of these calls in one step:
|
|
|
80
125
|
- `request_access({ service, reads: true, reason })` for each of `slack`, `notion` and `v0`, with a reason naming what the profile reads.
|
|
81
126
|
- The `onboarding_scripts` tool: it writes the skill's scripts into `/tmp/onboarding-skill/`, makes the `facts/`, `slices/` and `areas/` directories, and installs the `gh onboarding-facts` extension.
|
|
82
127
|
|
|
83
|
-
Then
|
|
128
|
+
Then three more steps, each started as soon as the one before returns:
|
|
129
|
+
|
|
130
|
+
1. Run `gh onboarding-facts --quick` with your `git__gh` tool. `--quick` returns in about 6 seconds and writes `facts/github/quick.json`: the user's open PRs that are approved (`approved`) or have changes requested (`changesRequested`), the 25 oldest review requests (`reviewRequested`) and their assigned issues (`assignedIssues`), each with its `total`; PRs carry `reviewDecision`, `mergeable` and `checks`.
|
|
131
|
+
2. Hand over the first task in its thread if there is one and post the first message. Nothing else starts before it posts, because each subagent started first delays it.
|
|
132
|
+
3. Run the full `gh onboarding-facts`, which takes about 80 seconds, and in the same step start the Slack base subagent and the leadership slice (step 3) if Slack is `approved`.
|
|
84
133
|
|
|
85
134
|
- **GitHub.** Run `gh onboarding-facts` with your `git__gh` tool, one command, no `repository`. Plain `gh` in your shell holds no credential. It reads 180 days and writes `facts/github/`: `base.json` (counts, per-repo totals, merged, open, review requests, assigned issues, unanswered mentions, teams, CODEOWNERS lines; open PRs carry `draft`, `reviewDecision`, `mergeable` and `checks`), `calendar.json` (contributions per day and week, and timestamped events), `reviews.json`, `issues.json`, and `repos/<owner>__<name>.json` for the top 5 repos by active days. `unreadable` in any file lists what could not be read. A failed command means GitHub was not read.
|
|
86
|
-
- **Slack base.** If Slack is `approved`, start one `agent` copy, `slack-base`, that reads `/tmp/onboarding-skill/slack-facts.callscript.js` and passes its text, unchanged, as `script` to `vercel-kit__execute`, handles the results listed below, saves the `output` whole as `facts/slack/base.json` (every list item, matching its `returned` count)
|
|
135
|
+
- **Slack base.** If Slack is `approved`, start one `agent` copy, `slack-base`, that reads `/tmp/onboarding-skill/slack-facts.callscript.js` and passes its text, unchanged, as `script` to `vercel-kit__execute`, handles the results listed below, saves the `output` whole as `facts/slack/base.json` (every list item, matching its `returned` count) in one write once the run has finished, and returns: the leadership slice's searches wait on that file. Give it these rules: never call `git__gh`, never post, and on `consent_required` or `refused` return the `approveUrl`, `run` and `refused.needed` without retrying. You post the link, and once the user approves you continue the same task by its `taskId` with `execute({ run })`. It gets 8 turns.
|
|
87
136
|
- **One access post.** If any `request_access` came back `pending` or `connection_required`, post one message with every pending `approveUrl` and one line each on what it unlocks. Then `request_status({ request })` for each until it is decided. A declined service is a "Could not tell" line, never a retry.
|
|
88
137
|
|
|
89
|
-
Slack's search limit is about 20 a minute per user. Only two scripts in the run call `search_messages`: the base script (18 searches) and the leadership slice's `lead-posts.callscript.js` (at most 10, started at least 60 seconds after the base finished). No other script searches.
|
|
138
|
+
Slack's search limit is about 20 a minute per user. Only two scripts in the run call `search_messages`: the base script (18 searches) and the leadership slice's `lead-posts.callscript.js` (at most 10, started at least 60 seconds after the base finished). The leadership slice starts beside the base, because its first two scripts don't search, and waits only before `lead-posts.callscript.js`. No other script searches.
|
|
90
139
|
|
|
91
140
|
The base script's results, which the `slack-base` copy handles:
|
|
92
141
|
|
|
@@ -102,14 +151,14 @@ From the files of step 1, pick the slices. A slice with no data isn't started, s
|
|
|
102
151
|
|
|
103
152
|
- **Channel clusters.** Group `own.channels` into at most 3 clusters by what they are about (team, project, support, social), judged from names and snippets.
|
|
104
153
|
- **Team channels.** Up to 3 channels whose name or purpose matches the user's team as `me.title` names it (Slack's `team` field holds the workspace id, not a team), or where they post most. List them with `conversations_info` only if you can't tell from the name.
|
|
105
|
-
- **Leadership.**
|
|
154
|
+
- **Leadership.** Already running since step 1; it picks its own channels and leads (step 3).
|
|
106
155
|
- **People.** Up to 15 user ids from `mentions.mentioners`, most first.
|
|
107
156
|
- **Notion queries.** Up to 5: the team's name, the team plus "strategy" or "roadmap", and the org's name.
|
|
108
157
|
- **Repos.** The files in `facts/github/repos/`.
|
|
109
158
|
|
|
110
159
|
## 3. Wave 1: one slice per source, all at once
|
|
111
160
|
|
|
112
|
-
Start every slice in one step, then wait. Each slice reads only its own inputs and writes `slices/<name>.md`: its findings as list items, each citing a URL from its facts, and a `## Could not tell` section. Tell each slice the user's login, Slack name, time zone and the window, the exact file paths it reads, the path it writes, and this format.
|
|
161
|
+
Start every slice in one step, then wait; the leadership slice is already running from step 1. Each slice reads only its own inputs and writes `slices/<name>.md`: its findings as list items, each citing a URL from its facts, and a `## Could not tell` section. A slice cites the URL itself, copied whole from its facts, query string included (a Slack reply permalink keeps its `?thread_ts=…`, or the checker can't find it). It never cites `fact:github/...`, `fact:slack/...` or any `fact:` path but `fact:local/`: those fail the checker, and every GitHub, Slack, Notion and v0 fact has a URL. Tell each slice the user's login, Slack name, time zone and the window, the exact file paths it reads, the path it writes, and this format.
|
|
113
162
|
|
|
114
163
|
| Area | Slice | Count | Reads | Runs as |
|
|
115
164
|
|---|---|---|---|---|
|
|
@@ -131,8 +180,8 @@ Start every slice in one step, then wait. Each slice reads only its own inputs a
|
|
|
131
180
|
**Kit slices** (`agent` copies) each run one script: read `/tmp/onboarding-skill/<script>` and pass its text as `script` to `vercel-kit__execute`, with the slice's `input`:
|
|
132
181
|
|
|
133
182
|
- `/tmp/onboarding-skill/team-channel.callscript.js`: `{ channel, days: 30 }`, the channel by id. If Kit answers that the script read more than it can keep, run it once more with `days: 14` and say so in the slice.
|
|
134
|
-
- `/tmp/onboarding-skill/leadership.callscript.js`, run twice. First with `{}`: it returns the user's channel memberships, and the slice picks up to 3 announcement or leadership channels from them (names like `announcements`, `eng-leads`, the team's `-leads` channel); this output is not saved. Then with `{ channels, days: 90 }`, channels by id: it reads the channels and returns their 20 most frequent posters as `candidates`, with title, team, `isBot`, `deleted` and post count, and searches nothing. The slice saves it as `facts/kit/leadership.json`, then judges from the candidates and the channels' messages who leads (what they announce, their titles, who others answer to), up to 10, with the known leads from step 2 first. Posting often is not leading: a bot, a deleted user or someone who only relays reminders is not a lead. It writes one line per chosen lead on why.
|
|
135
|
-
- `/tmp/onboarding-skill/lead-posts.callscript.js`: `{ leads, days: 90 }`, the ids the slice chose. Before it runs, the slice
|
|
183
|
+
- `/tmp/onboarding-skill/leadership.callscript.js`, run twice. First with `{}`: it returns the user's channel memberships, and the slice picks up to 3 announcement or leadership channels from them (names like `announcements`, `eng-leads`, the team's `-leads` channel); this output is not saved. Then with `{ channels, days: 90 }`, channels by id: it reads the channels and returns their 20 most frequent posters as `candidates`, with title, team, `isBot`, `deleted` and post count, and searches nothing. The slice saves it as `facts/kit/leadership.json`, then judges from the candidates and the channels' messages who leads (what they announce, their titles, who others answer to), up to 10, with the known leads from step 2 first. Posting often is not leading: a bot, a deleted user or someone who only relays reminders is not a lead. It writes one line per chosen lead on why. Before it judges, it reads `me` in `facts/slack/base.json` for the user's title and team once that file exists.
|
|
184
|
+
- `/tmp/onboarding-skill/lead-posts.callscript.js`: `{ leads, days: 90 }`, the ids the slice chose. Before it runs, the slice waits until `facts/slack/base.json` exists and 60 seconds have passed since it was written (`stat -c %Y`), checking in commands of at most 60 seconds, because the base's searches and these share Slack's limit of about 20 a minute. It saves the output as `facts/kit/lead-posts.json`.
|
|
136
185
|
- `/tmp/onboarding-skill/people.callscript.js`: `{ users }`
|
|
137
186
|
- `/tmp/onboarding-skill/notion.callscript.js`: `{ queries }`
|
|
138
187
|
- `/tmp/onboarding-skill/v0.callscript.js`: `{ days: 180 }`
|
|
@@ -161,20 +210,45 @@ Start three `agent` copies in one step. Each reads its area's slice files and wr
|
|
|
161
210
|
cd /tmp/onboarding-skill && node check-report.mjs --profile areas/*.md --facts facts
|
|
162
211
|
```
|
|
163
212
|
|
|
164
|
-
## 5.
|
|
213
|
+
## 5. Turn the areas into the read, in three passes
|
|
214
|
+
|
|
215
|
+
Three passes, one after another. Each runs as an `agent` copy that never calls `git__gh` and never posts. The critique is a fresh copy, so it sees only the draft and the files, not the reasoning that wrote the draft.
|
|
165
216
|
|
|
166
|
-
|
|
217
|
+
### 5a. Read pass
|
|
167
218
|
|
|
168
|
-
|
|
219
|
+
Start one `agent` copy, `read`, with 6 turns, and cancel it at 10 minutes. Keep its `taskId`: steps 5c and late answers continue it. Give it:
|
|
169
220
|
|
|
170
|
-
|
|
221
|
+
- the paths of the three area files, `facts/interview.md` (it may not exist yet), `facts/local/` and `facts/`;
|
|
222
|
+
- the current roster: your `list_agents` output, pasted in, with each bot's `name`, `role`, `kind`, `model`, `runsOn` and subagents;
|
|
223
|
+
- the standing decisions in effect, pasted in;
|
|
224
|
+
- the "`read.md` is the core read" section above, word for word, and the rules below.
|
|
171
225
|
|
|
226
|
+
It writes `read-draft.md` with the five sections of `read.md`, then returns its path.
|
|
227
|
+
|
|
228
|
+
- Every trait cites at least two different sources. Every row of `## Your team` names the trait behind it and the setting it changes: an agent entry in `hub.workspace.json` (`name`, `role`, `kind`, `model`, `runsOn`, `subagents`), a schedule, a standing decision, or a sandbox `prepare` step from the Mac half.
|
|
229
|
+
- It proposes at most four changes, because the user picks them from one `ask` (step 7).
|
|
230
|
+
- When the run has a first task, `## Act on first` links its thread (give it the link) as its first item, with what the task is waiting on. With no first task, the three items all come from the facts.
|
|
231
|
+
- It proposes only what the kit can create today. A bot that would need a new tool or a new kind of integration is a "Would need" line under the table, not a row.
|
|
172
232
|
- Judge; the scripts only counted. No scoring formula and no thresholds from code: say why in a sentence.
|
|
173
|
-
- Every list item cites at least one URL that is in the facts, or a `fact:` reference to a value in `facts/local/`, and no URL or reference appears that isn't. Never cite a web URL for a local count. State counts as the facts give them, with the window.
|
|
174
|
-
- Don't quote messages beyond the snippets, and don't name people beyond what a claim needs.
|
|
175
|
-
- A `## Could not tell` section: every `unreadable` source, `notJudged` mentions, that reactions were not read, the Slack window, a Kit grant the user declined, a slice that timed out, the Mac half if it hasn't reported.
|
|
176
233
|
|
|
177
|
-
|
|
234
|
+
### 5b. Critique pass
|
|
235
|
+
|
|
236
|
+
Start one more `agent` copy, `critique`, with 4 turns. Give it the paths of `read-draft.md`, the three area files and `facts/interview.md`. For each trait and each `## Your team` row it answers:
|
|
237
|
+
|
|
238
|
+
- Would this be true of most engineers on the user's team? If so, it is generic: cut it, or say what sharper claim the facts support.
|
|
239
|
+
- Do the two cited sources each support it, or does one only repeat the other?
|
|
240
|
+
- Does an area's `## Conflicts` section contradict it?
|
|
241
|
+
- Does the team change follow from the trait, or would the same roster be proposed for anyone?
|
|
242
|
+
|
|
243
|
+
It returns one line per item: `keep`, `cut` or `rewrite`, the item's heading or row, and one line on why. It writes nothing; you save what it returns, verbatim, to `/tmp/onboarding-skill/critique.md`, so a reviewer can check each cut against the draft. The model makes the judgment; no score or threshold decides.
|
|
244
|
+
|
|
245
|
+
### 5c. Write pass
|
|
246
|
+
|
|
247
|
+
Continue the `read` copy by its `taskId` with the critique's list and any late evidence that has arrived (below). It applies the critique once and writes:
|
|
248
|
+
|
|
249
|
+
- `read.md`: the five sections, with every `cut` gone and every `rewrite` rewritten.
|
|
250
|
+
- `facts.md`: the ten questions and the four more, answered from the area files, with a `## Could not tell` section listing every `unreadable` source, `notJudged` mentions, that reactions were not read, the Slack window, a Kit grant the user declined, a slice that timed out, and the Mac half if it hasn't reported.
|
|
251
|
+
- One schedule draft per recurring need it found (a morning pass over unanswered mentions, a weekly stale-PR pass), as `schedules/<bot>/<id>.md` for a bot on the current roster:
|
|
178
252
|
|
|
179
253
|
```md
|
|
180
254
|
---
|
|
@@ -186,48 +260,82 @@ The prompt the bot runs.
|
|
|
186
260
|
|
|
187
261
|
`cron` is five fields in UTC on a hosted deploy. Each draft says in its prompt which facts it reads and what it reports.
|
|
188
262
|
|
|
263
|
+
A schedule file has only `cron`, so it runs every time the cron matches: `0 14 23 11 *` runs every 23 November, not once. Never call a draft one-time. A need that runs once (a pre-freeze check) is not a draft: when you post step 7, arm it with `schedule__wake__create` in this thread, `expression: { type: "single", at, timezone }`, `until` a few minutes after `at`, and the prompt as its note, and list it in the Schedule table with When "once, <date>". If a draft must still end by opening a draft PR that deletes its own file, its prompt and every line of the read and the post that names it say it recurs until that PR is merged and deployed: the schedule keeps running until the deployment without the file is live.
|
|
264
|
+
|
|
265
|
+
Every run also writes `schedules/main/memory-review.md`, whatever else it found, so the team learns from the user's corrections from the first week:
|
|
266
|
+
|
|
267
|
+
```md
|
|
268
|
+
---
|
|
269
|
+
cron: "0 8 * * 1"
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
Read every thread from the last 7 days and find each place the human corrected a bot: a rule restated, an answer rejected, work redone their way. For each correction that should outlast its task, write `memory/<id>.md` (or `agents/<bot>/memory/<id>.md` when it is about one bot) with front matter `id`, `status: active`, `since` and `evidence` (the thread and message ids), then the rule in at most 3 lines. When it replaces an entry, set the old one's `status: superseded` and `superseded_by`; never rewrite it. Update `memory/human.md` with what the week showed about who the human is and how they work. Open one draft PR with only those files and never merge it. Post its link in the thread with one line per entry: the rule and the correction it came from. With no corrections, post that and open no PR.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Its row in the step 7 Schedule table says why it is there in the user's own words when the facts have them: link one or two of the user's corrections (a reply that tells a person or an agent to redo it their way) in "What it reports". With none in the facts, it says it starts from the corrections they make in this workspace.
|
|
276
|
+
|
|
277
|
+
Rules for both files:
|
|
278
|
+
|
|
279
|
+
- Every list item cites at least one URL that is in the facts, or a `fact:` reference: `fact:local/usage-<source>.json#<JSON pointer>` for a value in the Mac's files, `fact:interview/handoff` for the user's pick from the handoff `ask`. No URL or reference appears that isn't in the facts. Never cite a web URL for a local count. State counts as the facts give them, with the window.
|
|
280
|
+
- Don't quote messages beyond the snippets, and don't name people beyond what a claim needs. Both files name the user's repos and colleagues, so they are posted only in this thread and never committed.
|
|
281
|
+
|
|
189
282
|
```sh
|
|
190
|
-
cd /tmp/onboarding-skill && node check-report.mjs --profile
|
|
283
|
+
cd /tmp/onboarding-skill && node check-report.mjs --read read.md --profile facts.md --facts facts \
|
|
284
|
+
--critique critique.md --schedules schedules
|
|
191
285
|
```
|
|
192
286
|
|
|
193
|
-
|
|
287
|
+
`--read` checks citations and also fails a trait under `## How you work` that cites fewer than two different sources. `--critique` fails when `critique.md` is missing or holds no `keep`, `cut` or `rewrite` line; it checks presence only, not that the text is verbatim. `--schedules` fails a draft without a five-field `cron`, a missing `main/memory-review.md`, a draft that says it runs once, and a date-pinned or self-deleting draft whose prompt and read lines don't say it recurs until its deletion is merged and deployed. The copy fixes every line the checker prints and reruns until it prints nothing. When it returns, run the checker yourself once more; it must print nothing. Keep `read.md`, `facts.md`, `phases.log` and `critique.md`.
|
|
288
|
+
|
|
289
|
+
### Evidence that arrives late
|
|
290
|
+
|
|
291
|
+
Late evidence is the user's handoff answer (the whole `## handoff` entry of `facts/interview.md`: asked, offered and picked), or the Mac's `areas/llm-local.md`, that arrives after the read copy started. Evidence that is in before 5a starts goes to 5a like the rest: `facts/interview.md`, and `areas/llm-local.md` beside the three area files. Late evidence never goes into a pass that is running, and it is never dropped.
|
|
292
|
+
|
|
293
|
+
- **Before 5c starts**, it goes to 5c with the critique's list.
|
|
294
|
+
- **Once 5c has started**, wait for the read copy to return, then continue it by its `taskId` with only the new evidence. It judges again every trait, `## Your team` row and schedule draft the evidence bears on, including one it contradicts, rewrites them in `read.md`, updates the affected answers in `facts.md`, and returns the list of what it changed. When that list adds or rewrites a trait or a team row, start a fresh `critique` copy (5b) on just those items, giving it the same new evidence (for a handoff answer, the whole `## handoff` entry), and continue the read copy with its list. Run the checker until it prints nothing.
|
|
295
|
+
- **Once step 6 has opened its PR**, a refresh that adds, changes or removes a schedule draft changes the PR the same way: write, edit or delete its `agents/<bot>/agent/schedules/<id>.md` on the PR's branch, push, and watch its checks (`gh pr checks`) until they pass, as in step 6. A refresh never drops `memory-review`, so the PR always stays open. Before you touch its branch, check its state (`gh pr view <number> --json state`). If it is `MERGED`, never push to its branch: open a new PR from the default branch with only the changed, added or deleted schedule files, watch its checks the same way, and say the revised schedule is not deployed: the one running is the merged one, and the new one runs only once the user merges the new PR and it deploys. The changed schedule is posted only after its PR passes, or with what failed.
|
|
296
|
+
- **After step 7 has posted**, do the same, then post only what changed: the rewritten lines of the read, the changed team and schedule rows, and a new `ask` if the proposed team changed.
|
|
297
|
+
|
|
298
|
+
The run is over when the user picks from the `ask`. Until then keep `facts/`, because each refresh and its checker need it; delete it then. An answer after that is ordinary conversation, not evidence for the read.
|
|
194
299
|
|
|
195
300
|
## 6. Open the pull request, if the workspace has a repo
|
|
196
301
|
|
|
197
|
-
When the workspace is backed by a GitHub repo, open one PR on it that adds only the schedule drafts, as `agents/<bot>/agent/schedules/<id>.md`, and nothing from
|
|
302
|
+
When the workspace is backed by a GitHub repo, open one PR on it that adds only the schedule drafts, as `agents/<bot>/agent/schedules/<id>.md`, and nothing from `read.md` or `facts.md` (`gh pr create`). The user merging it is their approval; the deploy that follows is what makes the schedules run. The PR's checks include the deploy's build, which rejects a bad cron or a bot that does not exist: watch them (`gh pr checks`), fix the draft and push again until they pass, and say in the message if they do not. Without a repo the drafts stay in the thread and the message says so.
|
|
198
303
|
|
|
199
|
-
## 7. Post
|
|
304
|
+
## 7. Post the read, the team and the schedules
|
|
200
305
|
|
|
201
|
-
The user reads it cold, often only its first line (your writing rules). Write it to `/tmp/onboarding-skill/post.md` in this shape, load the forms skill for the tables, and check it:
|
|
306
|
+
The user reads it cold, often only its first line (your writing rules). This one message replaces any tour of the team: it shows the team as it should be for them. Write it to `/tmp/onboarding-skill/post.md` in this shape, load the forms skill for the tables, and check it:
|
|
202
307
|
|
|
203
308
|
```md
|
|
204
|
-
|
|
309
|
+
The read in two sentences: who they are and how they work, then the one thing to act on first.
|
|
205
310
|
|
|
206
311
|
---
|
|
207
312
|
|
|
208
|
-
|
|
|
313
|
+
| Bot | Change | Why |
|
|
209
314
|
|---|---|---|
|
|
210
|
-
(
|
|
315
|
+
(one row per current bot, "keep" or the change, then one row per proposed bot, each Why naming its trait)
|
|
211
316
|
|
|
212
317
|
| Schedule | Bot | When | What it reports |
|
|
213
318
|
|---|---|---|---|
|
|
214
|
-
(one row per draft)
|
|
319
|
+
(one row per draft, `memory-review` for `main` always among them, then one per one-run wake-up)
|
|
215
320
|
|
|
216
|
-
The drafts are in [this PR](...): merging it turns them on.
|
|
321
|
+
[The read](...) and [the facts it cites](...). The drafts are in [this PR](...): merging it turns them on.
|
|
217
322
|
(one line per source not read or grant declined: what was not read and what to do)
|
|
218
323
|
```
|
|
219
324
|
|
|
220
325
|
```sh
|
|
221
|
-
node /tmp/onboarding-skill/check-report.mjs --post /tmp/onboarding-skill/post.md
|
|
326
|
+
node /tmp/onboarding-skill/check-report.mjs --post /tmp/onboarding-skill/post.md \
|
|
327
|
+
--schedules /tmp/onboarding-skill/schedules
|
|
222
328
|
```
|
|
223
329
|
|
|
224
|
-
Fix every line it prints and rerun until it prints nothing, then post the file's text in this thread.
|
|
330
|
+
Fix every line it prints and rerun until it prints nothing, then post the file's text in this thread, with `read.md` and `facts.md` linked as uploads.
|
|
225
331
|
|
|
226
332
|
- The first bubble, everything above `---`, is at most two sentences.
|
|
227
333
|
- Below it, the two tables, then the lines under them and nothing else:
|
|
228
|
-
- The
|
|
334
|
+
- The links line. Without a repo, it says the drafts stay in the thread. If the PR's checks still fail after step 6, it says so and what failed, in place of "merging it turns them on".
|
|
229
335
|
- One line per source you could not read or Kit grant the user declined: what was not read and what they must do.
|
|
230
336
|
- If you handed the Mac half over in step 0 and that bot hasn't posted yet, one line: its half hasn't reported yet, and if the Hub app is closed on their Mac, it runs once they open it.
|
|
231
|
-
-
|
|
337
|
+
- No data tables in the chat: counts, windows, the ten answers and the "Could not tell" section stay in `facts.md`.
|
|
338
|
+
|
|
339
|
+
Then post one `ask` with one option per proposed change in the "Your team" table (an added, changed or removed bot), plus "None for now". An `ask` holds at most 5 options, so the read proposes at most four changes. The onboarding run never creates, changes or removes a bot. What the user picks is normal work in this thread: route it to the builder, which edits `hub.workspace.json` and the role files in its own PR, because a new bot is a deploy and a running cost.
|
|
232
340
|
|
|
233
341
|
Only the schedule files ever leave the thread.
|