Skip to content

Ask a human expert

When the knowledge base doesn’t have an answer, ask a person. Halyard routes the question to the right expert in Slack, returns their reply to the agent, and lets you save it so the next agent never has to ask again. Ask only after a real search miss — not as a first move.

This page is a rule you write for your agent. For how routing picks a person, see Experts & routing.

Ask a human when:

  • A focused search_knowledge (with the retry-with-fewer-filters habit) genuinely returned nothing.
  • The decision is judgment, preference, or undocumented context a human holds.

Don’t ask when:

  • The answer is in the codebase, the docs, or a knowledge entry you haven’t searched for yet.
  • You’re asking to confirm something you can verify yourself.
  1. See who’s available. list_team shows experts, their roles, and skills so you can target the question.

    list_team(role?, skill?, available_only?)
    {
    "members": [
    {
    "name": "David Kim",
    "roles": ["engineer"],
    "skills": ["React", "TypeScript", "Accessibility"],
    "availability": "ONLINE"
    },
    {
    "name": "James Okonkwo",
    "roles": ["architect", "engineer"],
    "skills": ["System Design", "Cloud Architecture", "Security"],
    "availability": "ONLINE"
    }
    ]
    }

    Roles are stored lowercase (engineer, pm, architect); skills are Title-Case domains (React, System Design). Filter by role to ask a category, skill to ask a specialist.

  2. Ask. ask_expert sends the question. Target it with role or skill so it reaches the right person; let Halyard pick the individual.

    ask_expert(prompt, role?, skill?, force_human?, options?, conversation_id?)
    ask_expert(
    prompt: "We're choosing between per-user OAuth and domain-wide sync for calendar import. Which did we land on, and why?",
    skill: "System Design"
    )
  3. Handle the return. ask_expert returns a discriminated union — branch on it:

    • Resolved from the knowledge base. Halyard checked the KB first and the question had an answer. You get the answer back immediately and no human was interrupted. Use it; you’re done. (Pass force_human: true only when you specifically need a person despite a KB match.)
    • Pending a human. No KB answer, so it routed to Slack. You get a conversation_id and a pending status. Move to step 4.
  4. Get the reply. Use check_response with the conversation_id. Pass wait: true to block for the reply instead of polling.

    check_response(conversation_id, wait?)
    check_response(conversation_id: "…", wait: true)
  5. Follow up if needed. Send more context or a clarifying question into the same thread with reply_to_expert.

    reply_to_expert(conversation_id, message)
  6. Capture the answer. When the reply changes what you do, file it with summarize_conversation so it becomes searchable knowledge. This step is not optional — see Capture what you learn.

    summarize_conversation(conversation_id, question, answer, source_url?, source_provider?)
Ask a human only after a genuine search_knowledge miss.
1. list_team(role|skill) to see who can answer; target the question.
2. ask_expert(prompt, role|skill). Branch on the return:
- Resolved from the knowledge base -> use the answer, you're done.
- Pending a human -> you get a conversation_id; continue.
3. check_response(conversation_id, wait: true). The wait returns in <=55s; if still
pending, do other work and poll again later. Never tight-loop.
4. reply_to_expert(conversation_id, message) to add context or clarify.
5. When the answer changes what you do, summarize_conversation(conversation_id,
question, answer) so the next agent finds it. Always capture.