copilot-harness-sdk · tutorials
Rung 2 · proved 5/5

Live tools plus skills, from one call

Rung 1's three agents with real tools, plus two SKILL.md skills on the same agent: the repo's hello-world and the community plan-create-prd. A brainstem builds the workspace, the tutorial script deploys it with the infrastructure profiles, and one proof run exercises all five capabilities.

Copilot Studio Build page of the Brainstem Starter Skills agent: five skills including hello-world and plan-create-prd, three tools, and instructions that begin with the agent's purpose
Five skills and three tools on one agent. The instructions open with the purpose passed to the builder.

What goes in

InputBecomes
hacker_news_agent.py, manage_memory_agent.py, context_memory_agent.pythe three live-tool profiles of rung 1
hello-world/SKILL.md (a RAR agent packaged as a skill, code included)InlineAgentSkill behavior, SKILL.md verbatim
plan-create-prd/SKILL.md (from coleam00/skills, unmodified)InlineAgentSkill behavior, SKILL.md verbatim
a purpose sentencethe first line of the instructions, followed by the routing the profiles and skills need

Build and deploy

From a brainstem, one tool call does everything (the brainstem's MakeCopilotStudioAgent writes the skill behaviors, hands the agent files to the tutorial with --agent-files and the behaviors with --skills-dir, and reports which profiles matched):

a.perform(name="Brainstem Starter Skills",
          description="You are a RAPP brainstem in Copilot Studio: you run the Hacker News, ManageMemory and "
                      "ContextMemory agents for real and you follow the hello-world and plan-create-prd skills exactly.",
          skills=["hello-world", "plan-create-prd"], agents=["HackerNews", "ManageMemory", "ContextMemory"],
          deploy=True, environment="https://<org>.crm.dynamics.com/", tenant="<tenant>")

Without a brainstem, the same deploy is the tutorial script with your own files:

node scripts/tutorial-rar.mjs --environment https://<org>.crm.dynamics.com/ --name "Brainstem Starter Skills" \
  --publisher-prefix rapp --schema-name rapp_BrainstemStarterSkills \
  --agent-files ./agents/hacker_news_agent.py,./agents/manage_memory_agent.py,./agents/context_memory_agent.py \
  --skills-dir ./skills --purpose "You are a RAPP brainstem in Copilot Studio ..." \
  --token-command "az account get-access-token --resource https://<org>.crm.dynamics.com/ --tenant <tenant> --query accessToken -o tsv"

./skills holds one <prefix>_<name>.mcs.yml per skill in the shape shown on rung 0. The script copies them into the workspace and adds one routing line per skill from its mcs.metadata.description.

Gotcha we hit: the brainstem found an older checkout of this SDK on the machine and deployed without the skills. Point COPILOT_HARNESS_SDK at the checkout you mean. The deploy log line skills from <dir>: hello-world, plan-create-prd is the tell.

What it looks like

Preview pane: the agent loads the fetch-hacker-news skill, runs the RAPP Hacker News workflow, and answers with a numbered list of three stories with points and comment links
Hacker News: the fetch-hacker-news skill loads, the flow runs through the custom connector, and the summary is rendered verbatim.
Preview pane: the harness tries to run the hello-world skill's script, the sandbox refuses, so it follows the skill's fallback and executes the perform method's logic itself, answering Hello, Ada! Welcome to the RAPP Agent ecosystem.
hello-world: the harness tried the skill's script, the sandbox refused, and the SKILL.md's own fallback ("read the code and do what perform does") produced the exact answer. Rung 3 is about making scripts run.
Preview pane: the agent loads the manage-memory skill, builds the annotation row with subject RAPP_MEMORY|scope=shared|type=preference, and calls Add a new row to selected environment
Memory write: the manage-memory skill builds the row and the Dataverse tool creates it.
Preview pane: the agent loads the recall-memory skill, decides on shared scope and full recall, calls List rows from selected environment, and parses the returned annotation rows
Memory recall: recall-memory queries the annotations table and parses the rows it wrote earlier.
Preview pane: the agent loads the plan-create-prd skill, restates the idea and asks five foundation questions: who specifically, the real cost, how they cope today, why now, why switch
plan-create-prd: a community skill followed as written, problem-first and under the word limit.

Prove it

ENTRA_CLIENT_ID=<client-id> ENTRA_TENANT_ID=<tenant> node tools/prove-copilot.mjs --mode 3p \
  --environment-url https://<org>.crm.dynamics.com/ --environment-id <env-id> \
  --bot-id <bot-id> --schema rapp_BrainstemStarterSkills --turns turns.json
PromptExpectedAnswer (16 Sep 2026)
What are the top 3 stories on Hacker News right now?numbered list, points, links"Top Hacker News stories: 1. **[Introducing System One Models and Jev](…)** — 699 points …"
Use the hello-world skill to greet Ada.Hello, Ada … Welcome to the RAPP Agent ecosystem"Hello, Ada! Welcome to the RAPP Agent ecosystem."
Remember this preference exactly: I read Hacker News every morningstored"Successfully stored preference memory in shared memory: …"
What do you remember about my reading habits?Hacker News, morning"Here's what I remember from shared memory: - Memory content (verbatim): "I read Hacker News every morning" …"
Use the plan-create-prd skill for this idea: an app that reminds remote workers to drink water. Start your interview now; ask your first questions in under 120 words.questions; problem, evidence, who"Got it — a hydration reminder app built for remote workers. Before I dig in: do you have any research …? **Foundation questions:** 1. Who *specifically* has this problem …"

The solution package

rappBrainstemStarterSkillsHarness.portable.zip: the imported solution with placeholders for the org URL and the connector id. Seven bot components: five skills and two Dataverse tools; the Hacker News flow and the connection references are provisioned by the deploy, or by hand as described in the manual way.