copilot-harness-sdk · tutorials
Rung 0 · proved 3/3

Skills only: SKILL.md files become one Copilot Studio agent

The smallest possible rung. Four skills and no infrastructure: each SKILL.md is copied verbatim into an InlineAgentSkill behavior and the instructions route to it. This is the agent whose solution you can export from Copilot Studio unchanged.

What goes in

InputBecomes
agent-author/SKILL.md, brainstem-doctor/SKILL.mdtwo InlineAgentSkill behaviors carrying the SKILL.md text verbatim
hello_world_agent.py, skill_advisor_agent.pytwo reasoning-only skills that carry the agent's contract and code (no live tool; the agent says so)
a one-paragraph descriptionsettings.mcs.yml: display name, schema name, CLICopilotRecognizer, Sonnet 4.6, instructions with one routing line per skill

Build and deploy

The workspace is generated by a RAPP brainstem's MakeCopilotStudioAgent tool (any brainstem that carries agents/copilot_studio_agent.py) and deployed through this repo's deploy script. Without a brainstem, write the same workspace by hand: one behaviors/<prefix>_<skill>.mcs.yml per skill, then deploy.

# through a brainstem's /chat (the tool takes the same arguments):
#   "Make a Copilot Studio agent named 'RAPP Brainstem Skills Demo' with the
#    brainstem-doctor and agent-author skills and the HelloWorldAgent and
#    SkillAdvisor agents; deploy it to https://<org>.crm.dynamics.com/"
#
# or directly from a built workspace:
node scripts/deploy-harness-agent.mjs --name "RAPP Brainstem Skills Demo" --publisher-prefix rapp \
  --schema-name rapp_RAPPBrainstemSkillsDemo --environment https://<org>.crm.dynamics.com/ \
  --workspace-dir ./workspace --work-dir ./.deploy/demo \
  --token-command "az account get-access-token --resource https://<org>.crm.dynamics.com/ --tenant <tenant> --query accessToken -o tsv"

A behavior file looks like this (the SKILL.md is indented under content, nothing rewritten):

mcs.metadata:
  componentName: "brainstem-doctor"
  description: "Check a RAPP brainstem's health: capabilities, quarantine, execution profile."
kind: InlineAgentSkill
content: |
  ---
  name: brainstem-doctor
  description: Check a RAPP brainstem's health ...
  ---
  # Brainstem doctor
  ...

Prove it

This agent has no tools, so anonymous Direct Line is enough: the prover flips the bot to no-auth, publishes, sends the turns through the SDK's agentic-directline mode, and restores the auth mode.

node tools/prove-copilot.mjs --environment-url https://<org>.crm.dynamics.com/ --environment-id <env-id> \
  --bot-id <bot-id> --schema rapp_RAPPBrainstemSkillsDemo --turns turns.json --no-auth --restore
PromptExpectedAnswer (15 Sep 2026)
What skills do you have? List their names.agent-author, brainstem-doctora table of the installed skills, both named
Greet Ada using your hello world capability and quote what it would say.Hello, Ada"Hello, Ada! Welcome to the RAPP Agent ecosystem." with the note that the helloworldagent skill was used
Is my brainstem healthy? Use the brainstem-doctor skill.a report naming skillsreports that the skill's scripts/check.py is not shipped in this deployment and gives a manual inspection instead

The third answer is the honest one: a SKILL.md that expects a script beside it cannot run that script in Copilot Studio unless the script ships too. That is rung 3.

The exported solution

rappRAPPBrainstemSkillsDemoHarness.exported.zip is the unmanaged solution exported from Copilot Studio with pac solution export, unmodified: one bot, four bot components. It contains no environment-specific values. Import it into any environment with the harness enabled and publish; nothing from RAPP is needed. See the manual way.