Skip to content

🚨 Mission 06: Generate Documents with a Python Skill

🕵️ CodenameOPERATION DOC ASSEMBLY⭐ Difficulty⏱️ Time 50 min 🧩 ProductsMicrosoft Copilot StudioMicrosoft Dataverse🏷️ TagsDocument GenerationPython🏭 IndustriesHR

Preview

This mission is in preview. Content may change and some steps might not work as intended.

🎯 Mission Brief

Welcome, Operative. In this mission you'll generate an interview-prep Word document with a fixed layout for a Job Application.

When a document's layout must be exact, a language model shouldn't format it because the result can change on every run. Instead, you'll build a skill that runs Python (python-docx) to apply the same sections, ordering, and styles to structured input. The agent still prepares the summary, evidence, and questions, so that wording can vary.

You'll draft this skill with the help of an agent - handing it the requirements and a document template and letting it write the Python, test it, and return a zipped skill - then add it to your Hiring Agent. A ready-made, tested version is provided as interview-prep-document-skill.zip so you can check your work against it or skip the authoring.

🔎 Objectives

In this mission, you'll learn:

  1. Why documents are generated by Python skills, not prompts
  2. How to draft a skill with a builder agent - the Python generator, the SKILL.md, and a packaged .zip
  3. How to test the skill by uploading it and generating a document through the agent
  4. How to add the skill to your Hiring Agent and generate a .docx from live Dataverse data
  5. How to verify the code-defined layout and extend it

🧠 A code-defined layout

A language model can draft content, but it does not guarantee identical document layout on every run. In this lesson, the agent gathers grounded content from Dataverse over MCP and assembles structured input. Python applies the spacing, tables, headings, and required text in code, and generates a Word document to download. The layout rules can therefore be reviewed, tested, and versioned like other source code, and will be the same each time the document is generated. Two runs can still contain different model-written summaries or questions, and the generated date reflects the day the script runs, but the document will always look the same - unlike a document the language model assembles itself, where every run comes out differently.

🐍 New to Python? Start here

This is the first mission that uses Python. You won't write any yourself - a builder agent drafts it in Lab 6.1 - but a little background helps you review what it produces.

  • Python is a popular, readable programming language. The generator runs server-side inside the agent and turns your structured data into an exact .docx.
  • A library (also called a module or package) is reusable, pre-written code you import and call instead of writing it yourself. The generator imports python-docx - the library that builds Word files - so one call like document.add_table(...) produces a real table with no formatting guesswork.
  • The code interpreter sandbox is the managed environment where the agent runs that Python. It already has Python and a set of common libraries installed, and it has no outbound internet access - so the agent can't pip install a package from the web at run time. A library is either already in the sandbox or bundled inside your skill package. python-docx and the other document libraries are already there, so the generator imports and uses them.

What's already in the sandbox

The sandbox ships with Python's standard library plus popular data and document packages, so most skills need no extra install. Commonly available:

PurposeExample modules
Everyday (standard library)json, csv, datetime, math, re, hashlib, sqlite3, zipfile
Data & analysispandas, numpy
Office documentspython-docx (Word), openpyxl (Excel), python-pptx (PowerPoint), a PDF library
Charts & imagesmatplotlib, qrcode, wordcloud

Exact availability can vary by tenant and changes over time, so if a skill needs something specific, confirm it first - ask the agent in Preview to import it (or run help('modules')) - and prefer pure-Python helpers you can bundle in the .zip over anything that expects a network install.

📦 The skill package

You'll build (or reuse) a skill package that's just a SKILL.md plus some Python scripts, zipped together. A tested reference is provided as interview-prep-document-skill.zip - unzip it to check your work against these files:

FilePurpose
SKILL.mdYAML name/description + the procedure the agent follows (gather data → write JSON → run Python → return the file)
generate_interview_doc.pypython-docx renderer with a fixed title block, Candidate, Role, Summary, Evaluation Criteria table, and 10 interview questions grouped by criterion

The document's Evidence level column (Strong / Moderate / Weak / Missing) uses the same four levels as the matching rubric from Mission 05 - so a candidate's evidence is described consistently whether you're scoring a match or briefing an interviewer.

Covered in Recruit

Revisit Recruit Mission 06: Add Skills for what belongs in each section of a SKILL.md.

At runtime the agent gathers the data, writes the JSON, and has the skill run the generator to produce the .docx - you never run Python yourself. A sample input (skill/interview_input.sample.json) and a generated example (skill/interview_prep.sample.docx) are included so you can see exactly what a correct result looks like.

📄 The document template

The template below is the exact layout the Python has to reproduce every time - the design target you hand to the agent in Lab 6.1. A real Word file works just as well, but this plain-text version is enough to produce an accurate generator, and only the «placeholder» values change per application.

text
Interview Preparation Pack                         [centered, bold, 22 pt]
«Candidate name» · «Job title»                       [centered, italic, 12 pt]
Application «A#####» · Generated «MMM dd, yyyy»       [centered, 9 pt]

Candidate
- Name: «Candidate name»
- Current title: «Current title»
- Email: «Email»
- Location: «Location»

Role
- Job Role: «J####» «Job title»
- Description: «Role description»

Summary
«One-paragraph recruiter summary grounded in the resume and role.»

Evaluation Criteria & Evidence
| Criterion   | Weight | Evidence level | Evidence                           |
| ----------- | ------ | -------------- | ---------------------------------- |
| «Criterion» | «nn»%  | Strong         | «Quote or summary from the resume» |
| «Criterion» | «nn»%  | Moderate       | «...»                              |
| ...         | ...    | Weak / Missing | ...                                |

Interview Questions
«Criterion 1» («nn»%)
  1. «Question grounded in that criterion»
       Maps to: «Requirement this question tests»
  2. «Question»
«Criterion 2» («nn»%)
  3. «Question»
  ... 10 questions total, grouped by criterion, highest-weight criteria first

AI-assisted preparation aid. Review for fairness and job-relevance before use.
Do not ask about protected characteristics.

The agent fills this template with information from the candidate's resume and the selected job role. It prepares a summary, compares the resume with the role's evaluation criteria, and writes ten interview questions, starting with the highest-weight criteria. The Python script puts that content into a consistent Word document, so interviewers can find the same sections in every pack.

🔄 Coming from the classic Operative course?

In the classic course this document was produced by an AI Builder prompt paired with a Word template, so the layout was defined in two places at once - part of it in the prompt, and part of it in the .docx. Moving a heading meant editing the Word file and re-testing the prompt against it.

Here the two jobs are separated. The agent gathers the grounded content through MCP, and a Python skill renders the document from a layout written in code. The layout is now text, so you can read it, review it, change one line of it, and get the same document out every time.

🧪 Lab 06 - Author a Python skill that renders the interview-prep document

Prerequisites

Before you start this lab you need:

  • The Hiring Agent with the intake, matching and application skills from Missions 02 and 05
  • At least one Job Application in Dataverse to generate a document for - Lab 5.5 created one
  • Permission to create a second agent in this environment, for the builder agent in Lab 6.1

To keep both the procedure and renderer in one reusable package, we'll create a builder agent that writes the Python generator and SKILL.md. Then you'll add that package to the Hiring Agent, generate a document from live Dataverse data, and inspect the layout it applies.

6.1 Draft the skill with a builder agent

We do not have to write the Python by hand. Next we will create a builder agent - a second Copilot Studio agent whose job is to write this skill - and use it as a pair programmer. It returns three artifacts: generate_interview_doc.py, SKILL.md, and a .zip containing both files.

  1. In the left navigation select Agents, New agent. Name it Skill Builder and give it instructions that tell it to write, run and package Python:

    text
    You are the Skill Builder. You help makers author Copilot Studio agent
    skills.
    
    You write Python that runs in the code interpreter sandbox and package the
    result as a .zip the maker can download.
    
    How to work:
    - Write complete, runnable code - never pseudocode or partial snippets.
    - Always run what you write and show the output before you claim it works.
    - The sandbox has no outbound internet, so only import modules that are
      already installed (for example python-docx, openpyxl, python-pptx, pandas)
      or pure-Python code you bundle yourself. Never pip install at run time.
    - A skill package is a .zip with SKILL.md at its root, alongside any scripts
      it needs.
    - SKILL.md begins with YAML frontmatter containing a name and a description
      that says when the skill should be used.

    The Skill Builder agent with its authoring instructions

  2. Open the draft agent's Preview and check it really can run code before you rely on it:

    text
    Run this Python and show me the output: print(sum(range(10))). Then tell me
    whether python-docx is importable in your sandbox.

    You should get 45 back and a confirmation that python-docx is available.

    Skill Builder confirms Python and python-docx availability

  3. Send the first prompt with the template inside it. Copy the block below, and where it says «paste the template here» paste the whole template from The document template above. The layout has to be in the conversation so the builder can refer back to it in the next step:

    text
    You are going to help me build a Copilot Studio skill that generates a Word
    document with Python.
    
    First, here is the layout the Python renderer must apply. The values in
    guillemets change per
    application:
    
    «paste the template here»
    
    Confirm you understand the layout, then wait - I'll tell you what to write
    next.

    It should read the layout back to you before writing anything:

    The builder agent confirming it understands the document template

  4. Now ask it to write the generator, pointing back at the template you just pasted:

    text
    Write a Python script `generate_interview_doc.py` that uses python-docx to
    build the interview-prep Word document exactly as in the template I just gave
    you. It reads a JSON file (path in argv[1]) and writes a .docx (path in
    argv[2]). Reproduce the centered Interview Preparation Pack title, candidate
    and role subtitle, and Application / Generated metadata. Follow with Candidate
    bullets (Name, Current title, Email, Location), Role bullets (Job Role,
    Description), Summary, Evaluation Criteria & Evidence, and Interview Questions.
    The table columns are Criterion, Weight, Evidence level and Evidence, with
    percent signs in the Weight values. Group 10 questions by criterion, highest
    weight first, with Maps to: lines when provided and the template's fairness
    reminder at the end. Apply the template's font sizes, alignment, bullet labels,
    Light Grid Accent 1 table style, and numbered questions. Use only Strong,
    Moderate, Weak and Missing. Keep the sections, ordering, table columns and
    styles in code, and document the exact JSON shape at the top of the file.
    Include the generation date supplied by the script at run time.
    Return generate_interview_doc.py as a downloadable file.
    Summarize its input contract and fixed layout in no more than five bullets.
    Do not paste the script or a verification table into the reply.

    Skill Builder reports the verified generator structure

  5. Make it test its own work before you trust it:

    text
    Create a small sample interview_input.json matching your JSON shape, run
    `python generate_interview_doc.py interview_input.json interview_prep.docx`,
    and confirm it produces a valid .docx with every section populated. Fix any
    errors. Inspect the generated document and report the section order, table
    shape, question count and grouping in a concise self-test report. Include the
    command result and any failures you fixed. Use exactly these headings: Section order,
    Table shape, and Question count and grouping for the report. Return the final script and the
    generated document as downloadable files. Do not paste the script into the reply.

    A good builder agent runs the script, then inspects the document it produced and reports what it checked - section order, table shape, question count and grouping:

    The builder agent verifying the document it generated

    It may do several steps at once

    A capable model often writes the script, tests it, drafts the SKILL.md and packages the zip in a single turn. That's fine - the prompts below still work as follow-ups, and asking for each artifact explicitly is how you check it really produced all three.

  6. Now we can use the Skill Builder agent to create a reusable skill based on its work. Ask it to write the SKILL.md - the procedure the Hiring Agent follows at runtime:

    text
    Write a SKILL.md with YAML frontmatter containing name: interview-prep-document
    and a description that
    triggers on "interview prep document for A#####". The body tells the agent
    to: read the ApplicationNumber; gather the Candidate, Resume, Job Role, and
    weighted Evaluation Criteria from the Dataverse MCP server; prepare content
    grounded only in that data (no protected-characteristic questions); write
    interview_input.json; run generate_interview_doc.py; and return
    interview_prep.docx. Note that python-docx is already available in the code
    interpreter sandbox, so import it directly - do not pip install at run time.

    Skill Builder returning SKILL.md as a downloadable file

  7. Now package everything up. Check the file list it reports - SKILL.md must be at the root - then download the zip:

    text
    Package the skill as interview-prep-document-skill.zip with SKILL.md at the
    root of the zip (not inside a folder), alongside generate_interview_doc.py
    and the sample JSON. Give me the zip to download and report its root file
    list.

    Skill Builder returning the packaged skill zip for download

Review everything the builder agent produces

Review everything it produces - check the Python for any obvious errors or omissions. You don't need to understand the code completely, but it should make sense based on what you asked for. Run it, and check the SKILL.md description is specific enough to trigger. The agent drafts fast, but you own correctness. Iterate with follow-up prompts until the sample document looks right.

Prefer not to author from scratch? The tested reference skill interview-prep-document-skill.zip is a working skill for reference. Compare your generated files against it, or just upload it in Lab 6.2 and come back to authoring later.

6.2 Add the skill to the Hiring Agent

The Hiring Agent cannot use the renderer until the package is part of its published skills. We'll upload the .zip, then let the agent run the Python.

  1. In the left navigation select Agents, open the Hiring Agent, and go to its Build tab. In the building-blocks panel on the right, find Skills and select .

    The Skills building block on the Build canvas

  2. Choose Upload a skill.

    Upload a skill (SKILL.md or .zip with Python)

  3. Drag in your interview-prep-document-skill.zip (or the provided reference zip). SKILL.md must sit at the root of the zip, not inside a nested folder - if it's nested, the skill fails to import. The skill then appears under Skills alongside resume-intake, role-matching and application-handling. Select Save.

    The Skills panel showing all four skills

  4. Publish the agent, confirming with Publish agent in the dialog.

    Publish control for deploying the uploaded document skill

6.3 Generate the document and compare the layout

With the skill uploaded and published, we'll generate a document from live data, inspect it, then run the same request again to compare and demonstrate that the output is consistent.

  1. In Preview, ask for the document. Replace A##### with a real ApplicationNumber from Mission 05 - your numbers will differ from the examples in this course:

    text
    Create an interview prep document for job application A#####.
  2. Watch the agent read the application, candidate, resume, role, and weighted evaluation criteria via the Dataverse MCP server, write interview_input.json, run generate_interview_doc.py, and return interview_prep.docx as a downloadable file. It loads the interview-prep-document skill, gathers the data, and returns the .docx with a grounded Evaluation Criteria table (evidence level per weighted criterion) and 10 questions mapped to the criteria:

    The generated interview_prep.docx attachment available to download from Preview

  3. Open the document and confirm the Candidate, Role, criteria table, and grouped questions are correct and grounded in the data.

    Generated interview preparation document open in Word

  4. Ask for the document again for the same application, then download the returned attachment. Open both downloaded documents and compare the centered title and subtitle, Application / Generated line, Candidate and Role bullets, section order, table columns, question groups, styles, and fairness reminder. These layout rules should match. The summary, evidence wording, or questions can differ because the agent prepares that JSON content, and the Generated date changes when the run day changes.

    Preview with the second generated document attachment

Deterministic Python code

Compare the two .docx files for the title block, section order, table columns, heading styles, and final fairness paragraph. Those come from generate_interview_doc.py. The agent supplies the summary, evidence levels, and questions, so compare those for grounding rather than exact wording.

Extending the skill. To change the layout, such as adding a scoring page, company branding, or a second language, go back to your builder agent, describe the change, and let it edit generate_interview_doc.py and re-package the skill for you to download again. Upload the new .zip over the old skill, publish, then ask the agent to regenerate the document and confirm the new layout.

6.4 Re-run the Hiring Agent's evaluations with the document skill

We gave the agent a new document-generation skill, so now we need to extend the test set and re-run it. The case we add checks the agent knows it can produce the document - not one that makes it generate a file live. An evaluation can call tools through a Connected profile, but its judge cannot open the returned .docx or verify its bytes and layout.

  1. In the left navigation select Agents, open the Hiring Agent, and go to its Evaluate tab.

    Agents list with the Hiring Agent ready to open

  2. Open your Hiring Agent baseline test set. Confirm it remains Single response, scored by Compare meaning with Pass score: 70/100.

    Hiring Agent baseline open with five conversations

  3. Add a case and enter the Question and Expected response below:

    #QuestionExpected answer contains
    6Without looking anything up, which of your skills generates documents, and what is that document used for?Names the interview-prep-document skill, the interview_prep.docx it produces from a Job Application, and that it's used to brief interviewers

    Six-case Hiring Agent regression saved

    Word this case carefully

    The case looks trivial, but two small changes in wording make it fail for reasons that have nothing to do with the skill:

    • Start with "Without looking anything up". Without that, the agent can read the question as being about live hiring data and call the Dataverse MCP tool. That makes the result depend on the selected profile's connection and on current records, instead of testing what the agent knows about its own skill. The opening phrase keeps this regression case stable.
    • Ask what the document is used for, not what sections it contains. The skill description tells the agent what the document is for, but not its internal layout - so asked about sections the agent correctly says it cannot be sure without reading the skill definition. The judge scores that partial answer as "one or more questions not answered" and the case fails.
  4. Save the test set, then select Evaluate to run the whole set. All six cases should pass and the score should remain at least 70% - describing the document skill needs no tool call:

    Hiring Agent test set green after adding the document case

When to use skills for document generation

A Python skill is the right choice when you need the same document every time. The model still prepares the content, which is probabilistic, but the layout is rendered by code the agent runs - so sections, ordering, table columns and styles come out identical on every run rather than being re-imagined from prose each time.

It isn't the only way to produce a document. A workflow can generate one too, and is the better fit when there is no conversation to attach the file to - an event fires, the document is created, and nobody is present. The trigger usually decides for you, because a request in chat points at a skill, an event points at a workflow.

✅ Mission Complete

Mission 06 is complete. You can now:

Code-defined document layout: You used Python to control the document's sections, ordering, and styles.

Authored with a builder agent: You drafted the Python generator and SKILL.md with a builder agent and packaged a .zip skill.

Tested & shipped: You uploaded and published the skill, then tested it by generating a document through the agent.

A grounded document: You generated the interview-prep .docx repeatedly from the same live Dataverse data

⏭️ Move to Automate Resume Intake with a Workflow mission

📚 Tactical Resources

🔗 Use code interpreter to generate and execute Python code

🔗 The new agent experience in Copilot Studio

🔗 python-docx documentation

Analytics