How to Build an Employee Policy Q&A Bot Over Your HR Handbook
Build a Spojit workflow that lets employees ask policy questions from Slack and get accurate, handbook-grounded answers by querying a persistent Knowledge collection built from your HR handbook.
What This Integration Does
HR teams answer the same handbook questions over and over: how much notice does a resignation need, how is annual leave accrued, what is the remote-work policy. This workflow turns your HR handbook into a searchable Knowledge collection in Spojit, then answers employee questions automatically. Someone posts a question, your workflow looks up the most relevant passages of the handbook, has Miraxa synthesise a grounded answer, and posts that answer back into Slack. Because every answer is drawn from the documents you embedded, the responses stay anchored to your actual policy rather than to general knowledge.
The run model is event-driven. A question arrives at a Webhook trigger (posted from a Slack workflow or slash-command integration), the workflow parses the question and the channel to reply in, queries a persistent Knowledge collection named for your handbook, and uses the slack connector's send-message tool to post the answer. The collection is persistent and workspace-scoped, so it is built once and reused on every run. Re-running is safe and idempotent for reads: each question is answered independently, no state is mutated in Slack beyond posting one reply, and updating the handbook is a separate one-time embed step that every future run picks up automatically.
Prerequisites
- A slack connection added under Connections -> Add connection, with permission to read user info and post messages to the channel you will answer in.
- A Webhook signing connection so the incoming question is verified. Use the Slack scheme if you post from a Slack-side integration, or the Custom scheme for a generic HMAC. See the related guide below on setting up a webhook connection.
- Your HR handbook as a file Spojit can embed (PDF, Word, Markdown, HTML, or Plain Text).
- A persistent Knowledge collection to hold the handbook. Create it under the Knowledge section of the sidebar before you build the workflow.
- The Slack channel ID (or a way to derive it from the incoming payload) where answers should be posted.
Step 1: Build the handbook Knowledge collection (one time)
Open the Knowledge section of the sidebar and choose New Collection. Name it something like hr-handbook, add an optional description, and confirm the embedding model (the embedding model is fixed at creation, so pick one and keep it). Gemini Embedding 001 is the default. Open the collection, choose Upload Document, drag in your handbook file, and choose Upload & Embed. Wait for the document status to move from PROCESSING to READY. The document table shows the chunk count once embedding completes. This persistent collection now lives at the workspace level and any workflow can query it.
If your handbook is split across several files (leave policy, code of conduct, IT policy), upload each one into the same collection so a single query searches all of them.
Step 2: Add a Webhook trigger to receive the question
Create a new workflow and set its trigger to Webhook. Attach the signing connection from your prerequisites so incoming requests are verified by HMAC. Copy the generated workflow URL and point your Slack-side integration (a slash command or a Slack workflow step) at it, sending a small JSON body that carries the question text and the channel to reply in. The trigger output is the parsed JSON body, available as {{ input }}. Design the body so you can read these fields:
{
"question": "How much notice do I give when resigning?",
"channel": "C0123456789",
"user": "U0456789012"
}
The trigger returns 202 with an executionId immediately, so the sender is not held open while the answer is generated. If your Slack integration can resend on retry, enable the opt-in event-id dedup on the trigger so a replayed delivery does not produce a duplicate answer.
Step 3: Query the handbook with a Knowledge node
Add a Knowledge node and set its mode to Query. In Collection, pick the persistent hr-handbook collection you built in Step 1 (not Transient, because the documents live beyond a single run). Set the Prompt to the employee's question, and instruct the synthesis to stay grounded in the retrieved passages:
Answer this employee policy question using only the HR handbook
passages provided. If the handbook does not cover it, say so plainly
and suggest contacting HR. Keep the answer under 120 words.
Question: {{ input.question }}
Set Result Count to control how many handbook passages feed the answer (the default is 5; raise it for broad policy questions). Choose the Model that synthesises the final answer. Optionally attach a Response Schema to force a structured result with separate answer and sourceSection fields. Set the Output Variable to policyAnswer so later steps can read {{ policyAnswer }}. This node is where Miraxa, the intelligent layer across your automation, turns retrieved handbook text into a clear reply.
Step 4: Guard for unanswerable questions with a Condition node
Add a Condition node after the Knowledge node so off-topic or out-of-scope questions get a graceful response instead of a guess. If you used a Response Schema, branch on a field such as {{ policyAnswer.covered }}; otherwise branch on whether the synthesised text indicates the handbook did not cover the question. Route the true branch (a valid policy answer) onward to Slack, and route the false branch to a Slack reply that points the employee to your HR contact. Keeping this branch explicit means employees always receive a reply, even when the handbook is silent on a topic.
Step 5: Post the answer back to Slack
Add a Connector node, choose your slack connection, and keep it in Direct mode since this is a single, predictable call. Select the send-message tool. Map the fields:
channelto{{ input.channel }}, the channel the question came from.textto the synthesised answer, for example{{ policyAnswer }}(or{{ policyAnswer.answer }}if you used a Response Schema).thread_tsif you want the answer to land as a threaded reply: pass the parent message timestamp through your webhook body and reference it here.
To address the asker by name, add a second Direct-mode Connector node before this one calling Slack's get-user-info tool with the {{ input.user }} id, then weave the returned name into your text. Direct mode here costs no AI credits and gives you a deterministic post.
Step 6: Keep the handbook current (maintenance run)
Policies change, so build a small separate workflow to refresh the collection. Use a Mailhook trigger or an Email trigger to receive the updated handbook, an Attachment node (Mailhook workflows only) to fetch the file bytes into {{ attachment.content }}, and a Knowledge node in Embed mode targeting the same hr-handbook collection with a fixed File Name. Because Embed mode overwrites a document when the file name already exists, re-sending the handbook replaces the old version cleanly, and every future Q&A run immediately searches the new text. Set the Document Type to match the file (PDF, Word, Markdown) and keep the Embedding Model the same as the collection's, since embed and query must use the same model.
Tips
- Use the same embedding model for the maintenance embed step and the original collection. Mismatched models degrade retrieval quality.
- Split a very large handbook into themed files (leave, conduct, IT) inside one collection. Retrieval still searches all of them, and you can re-embed just the section that changed.
- Tighten the Knowledge prompt to say "answer only from the provided passages" so Miraxa does not fill gaps with general knowledge.
- Post answers in a thread with
thread_tsto keep busy HR channels readable.
Common Pitfalls
- Querying a Transient collection by mistake. Transient collections auto-clean at the end of each run, so the handbook would vanish. Always pick the persistent
hr-handbookcollection in the Query node. - Missing Slack scope. If
send-messagereturns a permission error, the connection lacks rights to post in that channel. Re-check the connection's scopes. - Answering before embedding finishes. A query against a document still in
PROCESSINGreturns nothing. Confirm the document isREADYbefore going live. - Webhook replays. Without opt-in event-id dedup, a Slack retry can post the same answer twice. Enable dedup on the trigger if your sender retries.
Testing
Before exposing the workflow to employees, embed a single short policy document and run the workflow with a known question whose answer you can verify by eye. Send a test payload to the Webhook trigger with a question you know the handbook covers, then check the execution log to confirm the Knowledge node returned relevant passages and the send-message step posted to a private test channel. Try one question the handbook does not cover to confirm the Condition node routes it to the HR-contact reply. Once both paths behave, point your real Slack integration at the workflow URL and widen to your full handbook.