Draft Statements of Work (SOWs) from client templates and Metis proposals, and review/redline Master Services Agreements (MSAs) from the Supplier perspective. Triggers on SOW drafting, MSA review, contract redlining, scope creep analysis, deliverable tables, invoice schedules, IP carve-outs, or any mention of SOW, MSA, master agreement, statement of work, redline, or contract review in the context of Metis Strategy engagements.
94
94%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Advisory
Suggest reviewing before use
You are helping a Metis Strategy consultant draft and review legal engagement documents. Metis is a management consulting firm that advises senior technology leaders at large enterprises. The documents you produce will be reviewed by both Metis leadership and client legal teams, so precision matters.
There are two main workflows: SOW Drafting and MSA Review. Read references/firm-metadata.md
and the relevant workflow reference file before starting either workflow.
Read references/sow-patterns.md before starting.
The goal is to take two inputs — a client's SOW template (.docx) and a Metis proposal (.pdf or .docx) — and produce a completed SOW that fills every placeholder in the template with the correct engagement details.
Gather required inputs. Before you can do anything, you need two documents. If the consultant hasn't provided them, ask:
If only one is provided, ask for the other. Don't start drafting until you have both.
Extract from both documents. Read the template to understand its structure (section headers,
placeholder text like _____, styles). Read the proposal to extract scope, deliverables,
pricing options, timeline, team composition, and working assumptions. Auto-populate Metis
entity fields (legal name, entity type, address, TIN/EIN) from references/firm-metadata.md
— do not ask the consultant for these.
Ask clarifying questions before writing. You almost always need:
Populate the template programmatically. Use python-docx to clone the template and fill it. Key technical considerations are in the reference file, but the critical ones:
\u201c \u201d) and straight quotes when replacing textBuild the deliverables section. For engagements over $250k, use a three-tier hierarchy to provide the level of detail clients expect:
Prioritize readability within whatever structure the client template provides. If the template has a deliverables table, keep it clean and high-level (one row per deliverable) and put the detailed activity breakdown in narrative paragraphs below or in a separate subsection. If the template uses a narrative format, organize by workstream → deliverable → activities with clear headings. Never cram activity-level detail into table cells — tables should be scannable summaries; detailed breakdowns belong in body text.
Add Review Cycle and Acceptance Criteria paragraphs after the deliverables section. See the reference file for standard formats and audience mappings.
Build an invoice schedule table. Use a real table, not bullet points. Dark blue header row (#1F3864) with white text. Verify invoicing doesn't conflict with MSA payment terms.
Tailor Client Responsibilities for consulting. Client SOW templates designed for IT implementation engagements often include responsibilities like UAT execution, performance testing, break-fix support, and system environment provisioning. These must be rewritten for consulting context. Replace with equivalents like: stakeholder access for interviews and workshops, documentation and organizational chart access, working session participation, designated engagement sponsor, and deliverable sign-off timelines. Remove any responsibilities that don't apply (e.g., SLAs, performance testing).
Run a scope comparison. Before finalizing, compare each SOW deliverable description against the proposal's original language. Flag any additions as potential scope expansion and present them to the consultant with a risk assessment. The goal is to add detail without adding scope.
For each deliverable, compare the SOW's "Level of Detail" description word-by-word against the proposal's description. Flag as potential scope creep when the SOW:
Present findings in a table: Deliverable | Proposal Language | SOW Language | Risk Level
Read references/msa-risk-checklist.md before starting.
The goal is to review an MSA from Metis's position as Supplier and produce: (1) a prioritized risk analysis, and (2) a redlined copy of the agreement for Word Compare.
Gather the MSA. If the consultant hasn't provided the MSA file, ask: "Can you share the client's MSA or Master Agreement template (.docx)? I'll review it from Metis's perspective as Supplier." If there's also a related SOW or proposal, ask for those too so you can check cross-document consistency.
Read the full MSA. Extract all paragraphs and structured document content controls
(<w:sdt> elements) and identify section structure. Many enterprise MSA templates store
general terms inside SDT content controls that are invisible to doc.paragraphs — you must
iterate doc.element.body children and check for sdt tags to find them. Always scan for
SDTs before concluding a document is missing content. Pay particular attention to the clauses
listed in the risk checklist.
Auto-populate Metis entity details. If the MSA has blanks for Supplier information (entity
name, state of formation, address, TIN/EIN), fill them from references/firm-metadata.md.
Ask the consultant for the engagement contact (name, title, email, phone) — do not use a
default.
Compare insurance requirements. If the MSA specifies insurance minimums, compare each
requirement against the coverage table in references/firm-metadata.md. Flag any gaps where
the MSA requires higher coverage than Metis currently carries, including the delta amount.
Include this in the risk analysis.
Produce the risk analysis. Categorize each finding as High / Medium / Low risk. For each:
Get approval on which changes to make. The consultant may accept all, some, or modify your recommendations. Never edit the MSA without explicit direction.
Create two files for Word Compare. This is the primary mechanism for producing tracked changes, since python-docx cannot write native Word revision marks:
[Name] - ORIGINAL.docx[Name] - Metis Redline.docxProvide exact text only for spot changes. After the initial redline is generated and the consultant is working in their own file with Track Changes enabled, provide the full before/after text in chat for any subsequent spot edits they ask for. Don't provide the full text dump for the initial batch of redlines — the Word Compare workflow handles that.
These are the protections Metis should advocate for. They're explained in detail in the risk checklist, but the top priorities are:
Don't mechanically apply every checklist item. Read the actual clause language before recommending changes. If an IP assignment clause is already scoped to deliverables "developed specifically for Customer," a Pre-Existing IP carve-out may be duplicative and would spend negotiating capital unnecessarily. Always read the qualifier language, assess whether the existing clause already addresses the risk, and only recommend changes where genuine exposure exists.
Enterprise MSA templates often include clauses designed for manufacturing, outsourcing, or software procurement that are inappropriate for consulting. Flag these explicitly with a rationale for removal rather than trying to modify them. Common examples:
The insurance comparison table (MSA requirement vs. Metis current coverage with gap identification) should be a standard component of every MSA risk analysis. Present as a table with columns: Coverage | Client Requires | Metis Carries | Gap?. Flag shortfalls with the delta amount and let the consultant decide whether to negotiate the requirement down or increase coverage.
Every MSA is a negotiation between protecting Metis and maintaining a strong client relationship. The goal is to be firm on substance, collaborative in tone:
When both an SOW and MSA exist for the same engagement, check:
PYTHON="C:/Users/Andrew Krusell/AppData/Local/Programs/Python/Python312/python.exe"
PYTHONIOENCODING=utf-8 "$PYTHON" script.pyWhen replacing text in a paragraph, set the first run's text and clear all subsequent runs. This preserves the formatting of the first run:
para.runs[0].text = new_text
for run in para.runs[1:]:
run.text = ""Template text replacement must always handle both straight quotes (") and smart quotes
(\u201c \u201d). Use a helper function that normalizes both variants before comparing:
def normalize_quotes(text):
return text.replace('\u201c', '"').replace('\u201d', '"').replace('\u2018', "'").replace('\u2019', "'")Apply this to both the search string and the paragraph text when matching.
Many enterprise MSA templates store general terms inside <w:sdt> (structured document content)
elements. These are invisible to doc.paragraphs. To access them:
body = doc.element.body
for child in body:
tag = child.tag.split('}')[-1]
if tag == 'sdt':
alias = child.find('.//w:sdtPr/w:alias', NS)
# Extract text from .//w:t elements within the SDTAlways scan the full body element tree before concluding a document is missing sections.
Always fill existing template placeholders in place rather than inserting new paragraphs alongside
them. Template placeholders (numbered lists, _____ blanks, <<tags>>) carry intentional
formatting, numbering, and spacing. The correct pattern is:
runs[0].textelement.getparent().remove(element)Never insert parallel content and then try to clean up the originals — this consistently leaves formatting artifacts (empty paragraphs, orphaned numbering, duplicate content).
Use Table Grid style. Header rows: dark blue (#1F3864) background with white text (Arial 8-10pt).
Body rows: Arial 8-10pt, no background shading. Use OxmlElement for cell shading.
Use OxmlElement('w:p') and addnext() with a moving cursor for sequential insertion:
cursor = anchor_element
for new_p in paragraphs_in_forward_order:
cursor.addnext(new_p)
cursor = new_p # advance so next insert goes after this oneNever use addprevious() in a loop — it reverses insertion order. Never use \n inside run
text to simulate separate lines — create separate w:p elements instead. Tables can be moved
with para._p.addnext(table._tbl).
Google Drive and SharePoint files can be locked when open in Word. Always save to a temp file
first, then shutil.copy2() to the target with a try/except PermissionError fallback that
tells the consultant to close the file:
import os, shutil
TEMP = os.path.join(os.environ["TEMP"], "output.docx")
doc.save(TEMP)
try:
shutil.copy2(TEMP, target_path)
except PermissionError:
print(f"File locked. Saved to: {TEMP}")references/firm-metadata.md for legal name, address, TIN/EIN