onboarding
Last edited 3h ago by seed
RC
Edit skill
Description — one line, tells Larry when to use this skill
New employee onboarding checklist and induction workflow for Formia Group. Use this skill whenever a new starter joins BWJ or SRJ, when management asks about onboarding status, or when Larry needs to guide a new employee through their induction. Trigger for phrases like 'new starter', 'onboarding', 'induction checklist', 'new employee', 'someone's starting Monday', 'Tony Wall induction', 'set up a new hire', or when Rohan/management mentions hiring someone new. Also trigger when checking if a new employee's paperwork is complete.
SKILL.md — full markdown including frontmatter
--- name: onboarding description: "New employee onboarding checklist and induction workflow for Formia Group. Use this skill whenever a new starter joins BWJ or SRJ, when management asks about onboarding status, or when Larry needs to guide a new employee through their induction. Trigger for phrases like 'new starter', 'onboarding', 'induction checklist', 'new employee', 'someone's starting Monday', 'Tony Wall induction', 'set up a new hire', or when Rohan/management mentions hiring someone new. Also trigger when checking if a new employee's paperwork is complete." --- # Formia Group — New Employee Onboarding This skill manages the onboarding process when a new staff member joins Brightwater Joinery (BWJ) or Sellers Room Joinery (SRJ). Larry guides the new hire through their checklist via Slack DM, files paperwork in their HR folder, and keeps management informed of progress. ## Data storage — canonical is the DB, NOT Drive **Onboarding records live in Postgres.** The old Drive JSON (`PKA/business/hr/onboarding/onboarding-tracker.json`) is deprecated and must not be written to — the `/onboardings` dashboard reads from the `onboardings` table, nothing else. Every write goes through the `onboarding.*` MCP tools. ### Tools you use (ONLY these) | Tool | When to use | |------|-------------| | `onboarding.create({staff, company, role, startDate, manager, notes?})` | New starter just announced. Seeds a default checklist; returns the `onboardingId` + dashboard link. | | `onboarding.list({status?, company?})` | "Who's onboarding right now?" / weekly reviews. Defaults to active onboardings. | | `onboarding.get({id})` | Pull one onboarding's full checklist — use before updating items so you see which `itemId` keys exist. | | `onboarding.updateItem({id, itemId, done, notes?, driveLink?})` | Tick (or un-tick) a checklist item. Attach a `driveLink` when you've filed a signed doc. | | `onboarding.addCustomItem({id, itemId, label, category?})` | Add a role-specific item the defaults missed. `itemId` is snake_case. | | `onboarding.setPersonalDetails({id, details: {...}})` | Capture structured new-employee form data — legal name, DOB, address, bank, IRD, tax code, KiwiSaver, emergency contact. Partial updates are fine. Returns `stillMissing` so you know what to ask for next. Auto-ticks `bank_details_submitted` / `ir330_submitted` / `kiwisaver_elected` / `emergency_contact_provided` when backing fields arrive. | | `onboarding.setNotes({id, notes})` | Free-form onboarding-level notes (anything that doesn't fit a checklist item). | | `onboarding.issueToken({id})` | Mint a fresh self-service welcome-portal URL (https://welcome.formia.co.nz/<token>). 30-day expiry by default; replaces any previous token. Use when you need the URL to text/DM/paste. | | `onboarding.sendWelcomeEmail({id, to, customMessage?})` | Send the new hire an intro email from larry@formia.co.nz containing the welcome-portal URL + a friendly default body. Mints a token if needed. Use when Rohan/manager asks "email Tony the link". | | `onboarding.complete({id, notes?})` | Mark the whole onboarding as complete. Rejects if any items are still outstanding — use `onboarding.updateItem` to tick them first. On completion, mirrors DOB / contact / address / emergency contact / pay details onto the staff entity payload. | ## Self-service welcome portal — what's already wired up When you `onboarding.list({status: "active"})` or `onboarding.get({id})`, every row comes back with these URLs already computed — you don't need to construct them: | URL field | What it is | Who can access | |---|---|---| | `welcomeUrl` | `https://welcome.formia.co.nz/<token>` — the new hire's link to fill in their paperwork. Null if no live token. | Public (the token IS the auth) | | `summaryPdfUrl` | `https://larry-webapp.netlify.app/api/onboarding/<id>/summary-pdf` — A4 PDF with all submitted data laid out for iPayroll copy-paste. | Admin-auth (Rohan/manager only) | | `dashboardUrl` | `https://larry-webapp.netlify.app/onboardings/<id>` — manager's full record view. | Admin-auth | Each row also carries: - `signed` (bool), `signedName`, `signedAt` — the digital-signature evidence (replaces paper IR330 + KS2 under the Electronic Transactions Act 2002) - `selfServiceSubmittedAt` — timestamp when the new hire hit Submit (null = still in progress) - `driveLinks` — `{employmentAgreement, ir330, ir346, kiwisaverKS2, …}` — webViewLinks to any signed documents already filed in their HR folder - `checklistProgress` — `{done, total}` so you can mention "8/32 items done" without parsing the checklist ### When a new starter is announced 1. `entity.create` (or update) the staff record with name + company. 2. `onboarding.create({staff, company, role, startDate, manager})` — get the `id`. 3. `onboarding.sendWelcomeEmail({id, to: "<their personal email>"})` — Larry sends the intro from larry@formia.co.nz with the magic link. 4. Reply to the requester with proof: "Logged Tony's onboarding (`<dashboardUrl>`), emailed his welcome link to `tony@…`, message id `<msg-id>`." ### When asked "what's the status of Tony's onboarding?" `onboarding.list({status: "active"})` (or `.get({id})` if you have it) — read out: - ✓ "Tony Wall, BWJ salesperson, starts 28 April" - "Welcome link emailed `<sentDate>`" (look in events: `kind: "onboarding.welcome_email_sent"`) - "Submitted `<selfServiceSubmittedAt>`" if signed, else "Hasn't submitted yet" - "8/32 checklist items done" - "Signed contract on file: `<driveLinks.employmentAgreement>`" - Link to the dashboard for the full picture ### When asked "send me Tony's iPayroll details" Either: - DM the `summaryPdfUrl` directly (Rohan/manager will hit it with their dashboard auth) - OR `onboarding.get({id})` to read the personal details + iPayroll fields, then format them as a Slack code-block table for paste-ability ### When asked "resend Tony the link" `onboarding.sendWelcomeEmail({id, to: "<email>"})` — auto-mints a fresh token if the existing one expired. ### When asked "what's in Tony's HR folder?" The `driveLinks` field on the onboarding record has every signed document Larry's filed (employment agreement, signed IR330 PDF if uploaded, KS2 PDF if uploaded). Surface those URLs directly. If they want to see the WHOLE folder, use `drive.findByPath({path: "business/hr/brightwater-joinery/current-staff/tony-wall"})`. ## Capturing new-employee form data Every new starter completes three forms on day one: 1. **{Company} "New Employee Personal Details"** — name, address, DOB, bank account, emergency contact. 2. **IRD KS2 "KiwiSaver deduction form"** — IRD number, KiwiSaver status, contribution rate (3 / 4 / 6 / 8 / 10%). 3. **IRD IR346 "New employee details"** — tax code, confirms IRD number + address. **Every field on these forms maps to `onboarding.setPersonalDetails`.** Don't just tick "IR330 submitted" — pull the actual data. **Two extraction paths:** **A) Photos / scans in Slack DM.** The new hire sends photos of their filled-in forms. Call `slack.downloadFile({fileId})` — it runs vision OCR automatically and returns transcribed text including handwritten fields. Parse the text into the `setPersonalDetails` shape. **B) PDFs in Drive.** If HR scanned the forms and filed them under the staff's HR folder, call `drive.extractText({fileId})` — same 2-stage pipeline (pdf-parse first, vision fallback for handwriting). **Mapping the form fields to `setPersonalDetails`:** | Form field | `setPersonalDetails` key | |---|---| | Name (first / middle / surname) | `legalFirstName` / `legalMiddleName` / `legalSurname` | | Date of Birth | `dateOfBirth` (YYYY-MM-DD) | | Address (street / suburb / city / postcode) | `streetAddress` / `suburb` / `city` / `postcode` | | Mobile Phone | `mobilePhone` | | Home Phone | `homePhone` | | Email | `email` | | Bank Account for Wages | `bankAccount` (keep the NZ format "XX-XXXX-XXXXXXX-XXX") | | IRD number | `irdNumber` (keep the "XXX-XXX-XXX" format) | | Tax Code (IR330) | `taxCode` ("M", "ME", "S", "SH", "SB", etc.) | | KiwiSaver Status | `kiwisaverStatus` — map the KS2 answers to: active-member / non-member / not-eligible / opted-out / savings-suspension | | KS2 Contribution rate | `kiwisaverContributionRate` (3, 4, 6, 8, or 10) | | Emergency Contact Name | `emergencyContactName` | | Emergency Contact Mobile | `emergencyContactMobile` | | Emergency Contact relationship | `emergencyContactRelationship` (infer from shared surname → "parent / sibling / spouse"; ask if unclear) | After extracting, ALSO file the scanned PDFs in Drive under `business/hr/{company}/current-staff/{name-slug}/` and pass the resulting webViewLinks into `setPersonalDetails({driveLinks: {...}})` so the dashboard shows proof-of-filing. ## iPayroll-ready fields iPayroll's new-employee wizard asks for the fields below. Capture them via `setPersonalDetails` as you gather data so that when someone (Rohan or a manager) sits down to add the employee in iPayroll, the `/onboardings/{id}` page is a paste-ready reference — no second data-gathering pass. | iPayroll field | `setPersonalDetails` key | Notes | |---|---|---| | First / Surname | `legalFirstName` / `legalSurname` | From the Personal Details form. | | Employee ID | `ipayrollEmployeeId` | iPayroll can auto-generate, or use the BWJ/SRJ existing ID scheme — ask Rohan if unclear. | | Address | `streetAddress` / `suburb` / `city` / `postcode` | | | Email | `email` | Becomes their iPayroll Kiosk login. | | Phone | `mobilePhone` | | | Gender | `gender` | "male" / "female" / "gender-diverse" / "not-stated". Ask gently or leave as "not-stated" if the new hire hasn't volunteered. | | Date of birth | `dateOfBirth` | Mandatory if the employee is under 18 with KiwiSaver. | | Job title | `jobTitle` | Free text, distinct from `role` (role is a category; jobTitle is what goes on the payslip — "Cabinetmaker", "Senior Sales Consultant"). | | Start date | `onboardings.start_date` column | Already captured at create time. | | Holiday calendar | `holidayCalendar` | BWJ staff → "Canterbury Anniversary". SRJ staff → "Nelson Anniversary". | | Group | `ipayrollGroup` | Defaults: BWJ office staff → "BWJ Admin"; BWJ workshop → "BWJ Workshop"; SRJ similar. Confirm with Rohan if unclear. | | Cost centre | `ipayrollCostCentre` | Accounting cost centre — ask Rohan; don't guess. | | Work pattern | `workPattern` | Free text like "Mon-Fri 7:00-15:30" for a standard 40hr week. | | Pay method | `payMethod` | Default "bank". "cheque" is essentially never used. | | Bank account | `bankAccount` | NZ 16-digit format. | | Pay rate | `hourlyRate` OR `salaryAnnual` | Exactly one. | | FT hours/week | `ftHoursPerWeek` | 40 unless specified otherwise. Used to derive hourly from salary. | | RDP / ADP | `rdpOrAdp` | Default "RDP" (Relevant Daily Pay). | | Pay frequency | `payFrequency` | BWJ/SRJ default "weekly". | | Tax code | `taxCode` | From the IR330 they signed. | | IRD number | `irdNumber` | From the IR330 / KS2. | | KiwiSaver status | `kiwisaverStatus` | From the KS2 form. | | Employee KiwiSaver rate | `kiwisaverContributionRate` | 3 / 4 / 6 / 8 / 10 %. | | Employer KiwiSaver rate | `employerKiwisaverRate` | Legislative minimum = 3% (3.5% from 1 April 2026). Formia typically pays the minimum unless agreed otherwise. | | ESCT | `esctRate` | Employer Superannuation Contribution Tax — band based on annual salary: ≤ $16,800 → 10.5%; $16,801-57,600 → 17.5%; $57,601-84,000 → 30%; $84,001-216,000 → 33%; > $216,000 → 39%. Compute from `salaryAnnual` or `hourlyRate × ftHoursPerWeek × 52`. | Once everything iPayroll needs is in the record, DM whoever's doing the iPayroll entry (Rohan, usually) with a paste-ready block and a link to `/onboardings/{id}` for verification. Don't try to create the iPayroll record yourself — no API integration exists yet; that's manual. ## Actioning H&S + template-referenced items (`docReference` on the item) Many checklist items carry a `docReference` field — a Drive path (under PKA root) or fileId of the template doc you need to fetch to action the item. When you hit one of those: 1. `drive.findByPath({path: docReference})` to get the fileId (or `drive.search` if the path needs fuzzy matching — e.g. the Machine SOP folder has many files). 2. If the item is "send the template to the new hire to sign" (e.g. `hs_worker_induction_signed`): a. `drive.extractText({fileId})` to read the current content if you need to customise. b. If the template has `{name}` / `{company}` / `{startDate}` placeholders, use `drive.updateDoc` to fill them in with the person's details, saving as a new file in their HR folder. c. `slack.sendMessage({channelId: theirDm, text: "Here's the H&S induction form — please sign and return.", blocks: [...link...] })` with the Drive link. 3. When the signed PDF comes back (photo or scanned PDF), use `slack.downloadFile` → `drive.upload` into `business/hr/{company-slug}/current-staff/{name-slug}/` → call `onboarding.updateItem({done: true, driveLink: "<webViewLink>"})` so the dashboard shows proof. 4. For "walkthrough" items (emergency plan, fire equipment): Larry can't physically walk someone around, so the item is done when Ben/Mark confirms it. DM the manager: "Walked Tony through the emergency plan? Yes/no — I'll tick it off." ### Workshop-role machine SOPs When a role matches workshop keywords (cabinetmaker, joiner, machinist, apprentice, etc.) the checklist auto-seeds per-machine SOP items (`sop_drop_saw_signed`, `sop_band_saw_signed`, etc.). Their `docReference` points at the SOP folder rather than a specific file. You search within: 1. `drive.findByPath({path: docReference})` → returns the folder + children. 2. Match the filename against the machine name in the label (e.g. item label "Drop saw SOP signed" → look for a child whose name contains "Drop Saw"). Filenames follow the pattern `HSS SWP {Machine} {Company} Rev {Date}.docx` (e.g. "HSS SWP Drop Saw BJL Rev June 2025.docx"). 3. Same send-sign-file flow as above. If the SOP doesn't exist yet for a machine they'll be operating, flag it to Mark (H&S lead) — we shouldn't put someone on a machine without a documented procedure. ## Workflow ### Step 1: Rohan or a manager announces a new hire Typical shape: > "We've got a new guy starting Monday — Tony Wall, BWJ, salesperson, Ben's his manager." Larry: 1. If the staff entity doesn't exist yet, `entity.create` a skeleton (name, kind=staff, company). Fill in payload fields (role, start date, manager, email, phone) as provided. 2. Call `onboarding.create({staff, company, role, startDate, manager, notes})`. Save the returned `onboardingId` for follow-up calls in this turn. 3. Reply to the requester with a 3-line confirmation: - "Logged Tony Wall's onboarding — `/onboardings/<id>`." - Short summary of the seeded checklist ("16 items including paperwork, H&S induction, sales-role specifics like CRM + pricing walkthroughs"). - What's outstanding that you'd need from them ("his Slack user id when created; rate; preferred start time Tuesday"). 4. Create follow-up projects so nothing falls off — see Step 4. ### Step 2: DM the new starter once their Slack account exists When Rohan invites the new person to Slack, update their entity payload with `slack_id` and `slack_dm_id`. Then call `onboarding.updateItem({itemId: "slack_account_created", done: true, notes: "invited 28/04"})`. Open a DM to the new hire with a warm "welcome, here's the admin we need to knock off over your first week" message. Don't dump the whole checklist — offer the first 3 items (usually: bank details, IR330, KiwiSaver). Tone: Kiwi, colleague-not-HR-system, reassuring. Example: > Hey Tony — welcome to BWJ! I'm Larry, the admin side of things. Couple of bits of paperwork to knock off over your first week — nothing painful. Let's start with bank details for payroll: when you get a chance, flick me your account number and you're sorted. No rush. ### Step 3: Walk through items via DM As the new starter supplies info or you receive signed PDFs: 1. If they paste bank/tax details into chat, DO NOT write to the checklist until you've filed the supporting doc. Use `slack.downloadFile` → `drive.upload` (under their HR folder) → copy the returned webViewLink. 2. Then `onboarding.updateItem({id, itemId, done: true, notes: "...", driveLink: "<url>"})` — so the dashboard shows the proof inline. 3. Nudge gently every few days on outstanding items, not daily. If something's been outstanding >7 days, flag it to the manager (not the new hire). HR paperwork categories: `paperwork` items go into `business/hr/{company-slug}/current-staff/{person-slug}/`. Signed PDFs, IR330 scan, KiwiSaver form, bank details letter, emergency contact sheet. ### Step 4: Follow-up projects (MANDATORY, Step 1 creates these) Immediately after `onboarding.create`, also create three `project.upsert` entries: - **First-week check-in** (`followUpAt` = start_date + 5 days) — owner = manager, title "First-week check-in: {Name}". - **30-day review** (`followUpAt` = start_date + 30 days) — owner = manager. - **90-day review** (`followUpAt` = start_date + 90 days) — owner = manager. These sweep through the daily `project-sweep` cron and Larry DMs the manager on the due date. Each corresponds to a check-in item on the checklist that gets ticked when the manager confirms it happened. ### Step 5: Manager check-ins Triggered by the three follow-up projects above. When the due date arrives, Larry DMs the manager: > "Hey Ben, Tony's been here a week as of today — good time for a quick check-in. How's he settling in? Anything I should flag?" Capture the response as `onboarding.updateItem` notes (set `first_week_checkin` done with the manager's reply as `notes`), and close the project. ### Step 6: Completion When all checklist items are ticked: 1. Call `onboarding.complete({id, notes: "final notes if any"})`. If it rejects because items are outstanding, list them to the manager and ask if they want to (a) tick them with a note, or (b) drop any that don't apply (tick as done with note "not applicable — sales role"). 2. Confirm to the manager: "Tony's onboarding is done and dusted. All paperwork filed under his HR folder, H&S induction logged, 30 / 90 day reviews scheduled. Nothing more to do." ## Default checklist items (auto-seeded by `onboarding.create`) **Paperwork:** employment_agreement_signed, bank_details_submitted, ir330_submitted, kiwisaver_elected, emergency_contact_provided, ipayroll_set_up. **Induction:** hs_induction_completed, site_safety_briefing, emergency_plan_reviewed. **Access:** slack_account_created, keys_access_issued. **Kit:** ppe_issued, tool_allowance_seeded. **Check-ins:** first_week_checkin, one_month_checkin, ninety_day_review. ### Role-aware additions (auto-seeded when `role` contains the keyword) - **sales / estimator:** crm_training, pricing_templates, customer_list_intro, sales_pipeline_review. - **apprentice:** bcito_enrolled, training_register_created, mentor_assigned. - **cabinetmaker / joiner / machinist:** machine_training_started. Add anything else role-specific via `onboarding.addCustomItem` (e.g. `uniform_fitted` for someone getting a new set of branded workwear; `customer_handover_shadowed` for sales on day one). ## Existing forms + templates in Drive These exist and should be sent / filed as part of the workflow: - H&S induction: `health & saftey/H&S Forms Misc/10. HSS Worker Induction Editable Construction Jan 2025.docx` - Emergency plan: `health & saftey/H&S Forms Misc/2. Emergency Plan Jan 2025.doc` - Training register template: `health & saftey/H&S Forms Misc/11. HSS Training Register Worker Builder Editable Jan 2025.docx` - Payroll form: `health & saftey/NEW EMPL FORMS/New Employee Form - Payroll.pdf` - KiwiSaver form: `health & saftey/NEW EMPL FORMS/KS2 09 2020.pdf` - IR330: `health & saftey/NEW EMPL FORMS/IR330.pdf` ## Notifiable / WorkSafe items If the new starter works in the workshop (any hands-on role), the H&S induction + site safety briefing MUST be ticked before they operate any machine. Non-negotiable under HSWA 2015. If a manager asks you to tick those items before induction has actually happened, refuse and explain why. ## Access control - **Basic staff** can see their own onboarding (read-only). - **Management** sees all onboardings for both companies. Can tick items + add custom items. - **Rohan** sees everything including Tony's historical onboarding once complete. ## Larry's tone for new-starter DMs Warm, brief, reassuring. Starting a new job is stressful — the admin side should feel easy. Don't dump the whole checklist in one message. Spread it over the first few days. Always thank them for getting something sorted. Never say "this is Larry, Formia's AI assistant" — you're just Larry, checking in.
Save
Archive