Commit f8c7ab4
authored
feat(first-hour): do_first_hour_of_work tool + 7 persona plans + Slack DM renderer (Slice 15a) (#122)
The agent's first action on a fresh tenant is now do_first_hour_of_work,
a single-Sonnet-turn scaffold-driven runner that fires from main()
after the intro DM lands. By the time the user finishes setup, their
named persona has already pulled their morning, drafted their replies,
and DMed them with one click to approve.
Architect: phantom-cloud-deploy/local/2026-05-03-slice-15-first-hour-
of-work-architect.md.
What ships in this PR:
- src/persona/work-plans.ts: code-vendored TypeScript mirror of the
canonical persona-work-plans.json fixture (slice 15d-fixture, PR
#22 on phantom-cloud-deploy). Seven personas locked: sdr-lilian,
eng-cos-marcus, am-sloane, bdr-theo, sales-vp-priya, gtm-eng-ryan,
founder-asst-adrian. Byte-equal with the canonical for persona_id
literals and required_integrations arrays.
- src/persona/types.ts: FirstHourOfWorkInput/Output, DraftKind,
ReasonCode (11-code taxonomy locked at architect §7.2).
- src/persona/scaffold-prompt.ts: the verbatim 4-step prompt from
architect §1.4 with persona-driven substitutions.
- src/persona/runner.ts: end-to-end orchestrator. Resolves grants
via the env reader, filters required-integrations against the
resolved set, builds the prompt scaffold, races the LLM call
against a 60s AbortController, parses the JSON envelope, persists
drafts, sends the Block Kit DM, emits the five audit events.
- src/persona/llm-caller.ts: production LlmTurnCaller wrapping
runtime.handleMessage with a first-hour: session id prefix and
the JSON envelope parser.
- src/persona/failure-modes.ts: per-persona DM bodies for the six
failure modes (no_integrations_granted, all_pulls_zero_data,
llm_error_mid_flow, zero_drafts_from_nonzero_data, integration_
auth_expired, sixty_second_cap_hit). Verbatim from architect §6.
- src/persona/draft-store.ts: SQLite helpers for the firstboot ledger
and phantom_drafts table. Status transitions pending -> approved
-> sent.
- src/persona/firstboot-hook.ts: the index.ts entry point. NO-OP
when PHANTOM_PERSONA_ID is unset; idempotent on the firstboot
ledger.
- src/integrations/grants.ts: env-based reader of PHANTOM_GRANTED_
INTEGRATIONS with slack always granted (the wizard's slot 10
install is firstboot-baked).
- src/channels/slack/render-first-hour-dm.ts: Block Kit renderer
for the standard, fallback, and partial DM variants. Action_id
pattern phantom:draft:{draft_id}:{action} per architect §5.4.
- src/channels/slack/edit-modal.ts: views.open payload for the
draft edit modal.
- src/db/schema.ts: additive migrations (52-58) for firstboot_state
ledger columns and the new phantom_drafts table. Idempotent per
the migration-safety contract.
- src/channels/slack-actions.ts: Bolt regex handler for the
phantom:draft:{id}:{action} action_id pattern; per-draft buttons
flip to context blocks on click.
- src/channels/slack.ts: extends sendDm to accept optional Block Kit
blocks (the HTTP transport already accepted them; Socket Mode
catches up).
- src/index.ts: fires the firstboot hook after the intro DM lands.
- .github/workflows/ci.yml: persona-work-plans drift verifier step.
Runs the cross-repo guard from phantom-cloud-deploy in strict mode
once the canonical fixture lands on main.
- CLAUDE.md: First hour of work invariant section covering the
contract, idempotency, the action_id wire pattern, and the 60s
hard cap.
Coverage:
- 111 new tests across work-plans, scaffold-prompt, runner, failure-
modes, llm-caller, render-first-hour-dm, edit-modal, draft-store,
firstboot-hook, grants. Snapshot pins on the Block Kit JSON for
Lilian's full DM and the per-persona header/footer text shape.
- Happy path: drafts persist, DM lands, all five audit events fire
in order (start, pulls, drafts, dm, finish).
- Each of the six failure modes covered by its own runner test:
no_integrations_granted, all_pulls_zero_data, llm_error_mid_flow,
zero_drafts_from_nonzero_data, integration_auth_expired, sixty_
second_cap_hit. Plus slack_post_failed and persona_unknown.
- Defense-in-depth: a happy-path cycle across all seven personas
pinning that none degrades to a fallback DM.
Pre-push gate: bun typecheck clean, bun test 2537 pass / 0 fail
(+111 from this slice), bun lint clean.1 parent f26fd0c commit f8c7ab4
30 files changed
Lines changed: 4338 additions & 5 deletions
File tree
- .github/workflows
- src
- channels
- slack
- __tests__
- __snapshots__
- db
- __tests__
- integrations
- __tests__
- persona
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
37 | 55 | | |
38 | 56 | | |
39 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
291 | 291 | | |
292 | 292 | | |
293 | 293 | | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
294 | 306 | | |
295 | 307 | | |
296 | 308 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
55 | 80 | | |
56 | 81 | | |
57 | 82 | | |
| |||
255 | 280 | | |
256 | 281 | | |
257 | 282 | | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
258 | 368 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
290 | 290 | | |
291 | 291 | | |
292 | 292 | | |
293 | | - | |
294 | | - | |
| 293 | + | |
| 294 | + | |
295 | 295 | | |
296 | 296 | | |
297 | 297 | | |
| |||
Lines changed: 68 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
0 commit comments