
Nda Triage
- 44 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
nda-triage is a Claude Code skill that rapidly screens incoming NDAs with a GREEN/YELLOW/RED classification and a 10-point checklist.
About
nda-triage is a skill for rapid screening of incoming NDAs, classifying each as GREEN (standard approval), YELLOW (counsel review), or RED (significant issues). It uses a 10-point checklist to evaluate structure, definitions, obligations, carveouts, and problematic provisions, then recommends routing. It is flagged experimental and does not constitute legal advice. A user runs it when triaging or routing NDAs for approval.
- Rapid GREEN/YELLOW/RED classification of incoming NDAs
- 10-point screening checklist with pass/fail per criterion
- Routing recommendations by classification (business, counsel, senior counsel)
Nda Triage by the numbers
- 44 all-time installs (skills.sh)
- Ranked #1,686 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
nda-triage capabilities & compatibility
- Capabilities
- nda review · clause screening · contract triage
- Use cases
- research
What nda-triage says it does
Rapid NDA screening with GREEN/YELLOW/RED classification.
Uses a 10-point screening checklist to evaluate agreement structure, definitions, obligations, carveouts, and problematic provisions.
GREEN (standard approval), YELLOW (counsel review), or RED (significant issues)
npx skills add https://github.com/borghei/claude-skills --skill nda-triageAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 44 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Screen an incoming NDA into GREEN/YELLOW/RED and route it to the right approver.
Who is it for?
Triaging incoming NDAs and routing them to business approvers or legal counsel.
Skip if: Deep clause-by-clause negotiation (use nda-review) or binding legal advice.
When should I use this skill?
You are triaging NDAs, screening non-disclosure agreements, or routing NDAs for approval.
What you get
A GREEN/YELLOW/RED classification with a 10-point checklist and a routing recommendation.
- GREEN/YELLOW/RED classification
- 10-point compliance checklist
- Routing recommendation
By the numbers
- 10-point screening checklist
- 3-tier classification (GREEN/YELLOW/RED)
- 5 standard carveouts checked
Files
⚠️ EXPERIMENTAL — This skill is provided for educational and informational purposes only. It does NOT constitute legal advice. All responsibility for usage rests with the user. Consult qualified legal professionals before acting on any output.
NDA Triage
Rapid NDA screening tool that classifies incoming NDAs as GREEN (standard approval), YELLOW (counsel review), or RED (significant issues). Uses a 10-point screening checklist to evaluate agreement structure, definitions, obligations, carveouts, and problematic provisions.
---
Table of Contents
- Tools
- NDA Screener
- NDA Checklist
- Reference Guides
- Workflows
- Standard NDA Triage
- Bulk NDA Processing
- Routing Recommendations
- Troubleshooting
- Success Criteria
- Scope & Limitations
- Anti-Patterns
- Tool Reference
---
Tools
NDA Screener
Scans NDA text for red flags and outputs GREEN/YELLOW/RED classification with reasoning.
# Screen an NDA file
python scripts/nda_screener.py nda_draft.txt
# JSON output for integration
python scripts/nda_screener.py incoming_nda.md --json
# Save screening results
python scripts/nda_screener.py nda_draft.txt --output screening.json --jsonWhat it detects:
- Missing standard carveouts (public knowledge, prior possession, independent development, third-party receipt, legal compulsion)
- Non-solicitation and non-compete clauses
- Perpetual confidentiality obligations
- Overbroad definition of confidential information
- Residuals clauses granting usage rights to ideas/concepts
- IP assignment or license grants
- Liquidated damages provisions
- Unlimited audit rights
- One-sided obligations
Classification Rules:
| Level | Criteria | Routing |
|---|---|---|
| GREEN | All 5 carveouts present, no problematic provisions, standard structure | Business approver; no counsel needed |
| YELLOW | 1-2 missing carveouts, minor problematic provisions, or non-standard terms | Legal counsel review within 48 hours |
| RED | 3+ missing carveouts, non-compete/non-solicitation, IP assignment, perpetual term with no exit | Senior counsel review; do not sign |
---
NDA Checklist
Generates a compliance checklist for an NDA, checking all 10 screening criteria with pass/fail status.
# Generate checklist for an NDA
python scripts/nda_checklist.py nda_draft.txt
# JSON output
python scripts/nda_checklist.py nda_draft.txt --json
# Save checklist
python scripts/nda_checklist.py nda_draft.txt --output checklist.json --json10-Point Screening Criteria:
| # | Criterion | What It Checks |
|---|---|---|
| 1 | Agreement Structure | Mutual vs. one-way; parties identified; purpose stated |
| 2 | Definition of Confidential Info | Scope, specificity, marking requirements |
| 3 | Obligations | Standard of care, use restrictions, disclosure limits |
| 4 | Standard Carveouts | 5 required: public knowledge, prior possession, independent development, third-party receipt, legal compulsion |
| 5 | Permitted Disclosures | Representatives, advisors, affiliates with need-to-know |
| 6 | Term & Duration | Reasonable term, survival period, obligations after expiry |
| 7 | Return/Destruction | Obligation to return or destroy upon request/termination |
| 8 | Remedies | Injunctive relief, damages, indemnification scope |
| 9 | Problematic Provisions | Non-solicitation, non-compete, exclusivity, residuals, IP assignment, audit rights |
| 10 | Governing Law | Jurisdiction, dispute resolution mechanism |
---
Reference Guides
NDA Screening Criteria
references/nda_screening_criteria.md
Complete evaluation reference covering:
- All 10 screening criteria with detailed sub-items
- GREEN/YELLOW/RED classification rules with specific examples
- Common NDA issues with standard positions
- Redline approaches for common problems
---
Workflows
Standard NDA Triage
1. Receive NDA -- Save as .txt or .md file 2. Screen -- Run nda_screener.py for quick RED/YELLOW/GREEN classification 3. Checklist -- Run nda_checklist.py for detailed 10-point evaluation 4. Route -- Follow routing recommendations based on classification 5. Track -- Log screening result and routing decision
Bulk NDA Processing
# Screen multiple NDAs
for nda in ndas/*.txt; do
echo "=== $nda ==="
python scripts/nda_screener.py "$nda"
echo ""
done
# Generate JSON report for all NDAs
for nda in ndas/*.txt; do
python scripts/nda_screener.py "$nda" --json --output "results/$(basename $nda .txt).json"
done---
Routing Recommendations
| Classification | Approver | Timeline | Escalation |
|---|---|---|---|
| GREEN | Business owner or designated approver | Same day; sign within 24 hours | None required |
| YELLOW | Legal counsel review | 48-hour turnaround | Escalate to senior counsel if no response in 72 hours |
| RED | Senior legal counsel | 5 business day turnaround | Escalate to General Counsel if deal-critical |
GREEN Fast-Track Conditions
All of the following must be true for GREEN classification:
- Mutual NDA (both parties bound)
- All 5 standard carveouts present
- No non-solicitation, non-compete, or exclusivity clauses
- No IP assignment or license grants
- No residuals clause
- Term is 2-5 years (not perpetual)
- Return/destruction obligation present
- Standard remedies (injunctive relief, no liquidated damages)
RED Escalation Triggers
Any one of the following triggers RED classification:
- Non-compete clause of any scope
- Non-solicitation clause covering employees or customers
- IP assignment or broad license grant
- Missing 3 or more standard carveouts
- Perpetual obligations with no termination right
- Liquidated damages for breach
- Exclusivity provision
---
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Screener classifies everything as YELLOW | NDA uses non-standard formatting that breaks pattern matching | Ensure NDA is clean plain text; remove PDF artifacts and headers/footers |
| Missing carveouts false positive | Carveouts are present but use unusual language | Review the full "Exceptions" or "Exclusions" section manually; the screener checks common phrasings |
| Non-compete not detected | Non-compete is embedded in definitions or obligations section rather than standalone | Search the full document for "compete", "competitive", "restrict" manually |
| Checklist shows PASS but screener shows RED | Checklist evaluates presence; screener evaluates content quality | Use both tools together; the screener's RED overrides checklist PASS |
| Script errors on large files | NDA text exceeds expected size (>100KB) | Ensure the file contains only the NDA text, not appendices or exhibits |
---
Success Criteria
- NDA triage under 5 minutes: Automated screening replaces 30-minute manual review.
- Zero missed RED-severity issues: Every non-compete, IP assignment, and missing carveout is flagged.
- GREEN NDAs signed within 24 hours: Fast-track routing eliminates bottleneck for standard agreements.
- YELLOW NDAs resolved within 48 hours: Counsel review turnaround meets SLA.
- Consistent classification across reviewers: 10-point checklist eliminates subjective "looks fine" approvals.
- 100% of NDAs screened before routing: No NDA reaches an approver without automated triage.
---
Scope & Limitations
Covers:
- Pattern-based screening of NDA text for structural issues and problematic provisions
- 10-point compliance checklist against standard NDA requirements
- GREEN/YELLOW/RED classification with routing recommendations
- Detection of non-solicitation, non-compete, IP assignment, residuals, and other problematic clauses
- Missing carveout identification
Does NOT cover:
- Legal advice -- classification is a screening aid, not a legal opinion
- Negotiation or redlining -- use
nda-reviewfor deep clause analysis and redline generation - Multi-party NDAs -- optimized for bilateral (two-party) agreements
- Industry-specific NDA requirements (healthcare, defense, government) -- patterns target commercial NDAs
- Non-English NDAs -- pattern matching is English-language only
---
Anti-Patterns
| Anti-Pattern | Why It Fails | Better Approach |
|---|---|---|
| Signing GREEN-classified NDAs without any human review | Automated screening cannot catch business-context risks (e.g., NDA with a direct competitor) | GREEN classification means low legal risk, not zero risk; business approver must still review |
| Using triage as a substitute for deep NDA review on complex deals | Triage checks structure and red flags, not clause quality or negotiation position | Run nda-review skill for M&A, joint venture, or high-value partnership NDAs |
| Ignoring YELLOW classifications because "it's just an NDA" | YELLOW items like missing carveouts or residuals clauses create real legal exposure | Route all YELLOW NDAs to counsel; missing independent development carveout alone can cost millions |
| Treating all NDAs as equal regardless of counterparty relationship | NDA with a startup partner requires different scrutiny than NDA with a Fortune 500 vendor | Adjust review depth based on counterparty, deal value, and information sensitivity |
---
Tool Reference
nda_screener.py
Purpose: Scans NDA text for red flags and problematic provisions. Outputs GREEN/YELLOW/RED classification with detailed reasoning.
Usage:
python scripts/nda_screener.py <nda_file> [--json] [--output FILE]Flags:
| Flag | Short | Default | Description |
|---|---|---|---|
nda_file | (positional) | Path to NDA text file (.txt or .md) | |
--json | off | Output in JSON format | |
--output | -o | (stdout) | Write output to file |
Example Output (JSON):
{
"file": "vendor_nda.txt",
"classification": "YELLOW",
"red_flags": [
{
"id": "missing_carveout_independent_development",
"severity": "YELLOW",
"description": "Missing independent development carveout",
"recommendation": "Add standard independent development exception"
}
],
"carveouts": {
"public_knowledge": true,
"prior_possession": true,
"independent_development": false,
"third_party_receipt": true,
"legal_compulsion": true
},
"summary": "1 missing carveout; no critical issues. Route to counsel for review."
}---
nda_checklist.py
Purpose: Generates a 10-point compliance checklist for an NDA, evaluating each screening criterion as PASS/FAIL with notes.
Usage:
python scripts/nda_checklist.py <nda_file> [--json] [--output FILE]Flags:
| Flag | Short | Default | Description |
|---|---|---|---|
nda_file | (positional) | Path to NDA text file (.txt or .md) | |
--json | off | Output in JSON format | |
--output | -o | (stdout) | Write output to file |
Example Output:
NDA COMPLIANCE CHECKLIST
========================
File: vendor_nda.txt
Overall: YELLOW (8/10 PASS)
# Criterion Status Notes
1 Agreement Structure PASS Mutual NDA; both parties identified
2 Definition of Confidential PASS Reasonably scoped with marking requirement
3 Obligations PASS Standard of care; use restrictions present
4 Standard Carveouts FAIL Missing: independent development
5 Permitted Disclosures PASS Representatives and advisors covered
6 Term & Duration PASS 3-year term with 2-year survival
7 Return/Destruction PASS Return or destroy within 30 days
8 Remedies PASS Injunctive relief; no liquidated damages
9 Problematic Provisions FAIL Residuals clause detected
10 Governing Law PASS Delaware law; state courtsNDA Screening Criteria
Complete evaluation reference for rapid NDA triage. Covers all 10 screening criteria with detailed sub-items, classification rules, and redline approaches for common issues.
---
Table of Contents
- Classification Framework
- Criterion 1: Agreement Structure
- Criterion 2: Definition of Confidential Information
- Criterion 3: Obligations
- Criterion 4: Standard Carveouts
- Criterion 5: Permitted Disclosures
- Criterion 6: Term and Duration
- Criterion 7: Return and Destruction
- Criterion 8: Remedies
- Criterion 9: Problematic Provisions
- Criterion 10: Governing Law
- Common NDA Issues and Redline Approaches
---
Classification Framework
Overall Classification Rules
| Classification | Trigger | Routing | Timeline |
|---|---|---|---|
| GREEN | All 10 criteria pass; no problematic provisions; all 5 carveouts present | Business approver | Sign within 24 hours |
| YELLOW | 1-2 criteria fail; minor issues detected; 1-2 missing carveouts | Legal counsel | Review within 48 hours |
| RED | 3+ criteria fail; critical provisions (non-compete, IP assignment); 3+ missing carveouts | Senior counsel | Review within 5 business days |
Per-Criterion Classification Impact
| Criterion | GREEN | YELLOW | RED |
|---|---|---|---|
| Agreement Structure | Parties, purpose, direction clear | One element unclear | Parties unidentified or structure ambiguous |
| Definition | Bounded, with marking requirement | Broad but reasonable | "All information of any kind" with no limits |
| Obligations | Standard of care, use restriction, disclosure limits | One element missing | No obligations specified |
| Standard Carveouts | All 5 present | 1-2 missing | 3+ missing |
| Permitted Disclosures | Representatives with need-to-know | Representatives without need-to-know | No permitted disclosures (or overly broad) |
| Term & Duration | 2-5 years with reasonable survival | 1-year or 7+ year term | Perpetual with no termination |
| Return/Destruction | Return or destroy with certification | Return or destroy without certification | No return/destruction obligation |
| Remedies | Injunctive relief, no liquidated damages | Injunctive relief with broad indemnification | Liquidated damages or penalty clauses |
| Problematic Provisions | None detected | Residuals or audit rights | Non-compete, non-solicitation, IP assignment, exclusivity |
| Governing Law | Favorable or neutral jurisdiction | Unfamiliar but acceptable jurisdiction | No governing law or hostile jurisdiction |
---
Criterion 1: Agreement Structure
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Parties | Full legal names with entity type | Vague references ("the parties") |
| Direction | Clearly mutual or one-way | Ambiguous (purports to be mutual but obligations are one-sided) |
| Purpose | Specific purpose stated | No purpose or overly broad ("any purpose") |
| Effective Date | Clearly stated or determinable | Missing or ambiguous |
| Signatures | Authorized signatories identified | No signature block or unauthorized signer |
Mutual vs. One-Way
| Type | When Appropriate | Key Difference |
|---|---|---|
| Mutual (Bilateral) | Both parties will share confidential information | Both parties have equal obligations |
| One-Way (Unilateral) | Only one party discloses confidential information | Only receiving party has obligations |
Watch for: NDAs labeled "mutual" but with one-sided obligations. Check that both parties are bound by the same restrictions.
---
Criterion 2: Definition of Confidential Information
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Scope | Bounded to information related to the stated purpose | "All information of any kind, in any form" |
| Marking | Written info marked "Confidential"; oral confirmed in writing within 10-30 days | No marking requirement (everything is confidential) |
| Form | Covers written, oral, visual, and electronic | Limited to only one form |
| Specificity | Categories of information listed | Vague catch-all with no categories |
| Exclusions | Standard carveouts referenced | No exclusions from definition |
Definition Scope Spectrum
| Scope Level | Example Language | Classification |
|---|---|---|
| Narrow (best) | "Information specifically designated as Confidential and relating to [purpose]" | GREEN |
| Standard | "Non-public information relating to the business, technology, or finances of the disclosing party" | GREEN |
| Broad | "Any and all information disclosed by either party, whether written, oral, or visual" | YELLOW |
| Overbroad | "All information of any kind, nature, or description, in any form or medium, relating to the disclosing party or its business" | YELLOW/RED |
---
Criterion 3: Obligations
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Standard of Care | "Reasonable care" or "same degree of care as own confidential information" | "Absolute" or "best efforts" to protect |
| Use Restriction | Use solely for the stated purpose | No use restriction |
| Disclosure Limits | Limit to need-to-know personnel | No limits on internal disclosure |
| Written Agreements | Require written confidentiality agreements from recipients | No downstream protection required |
| Security Measures | Reasonable technical and organizational measures | Specific expensive security requirements |
Standard of Care Comparison
| Standard | Meaning | Appropriateness |
|---|---|---|
| "Reasonable care" | Objectively reasonable measures | Market standard; recommended |
| "Same degree of care" | Same as party uses for own information | Common; acceptable |
| "Best efforts" | Highest possible standard | Overly burdensome; negotiate down |
| "Absolute" | Guarantees no disclosure | Unacceptable; no party can guarantee |
---
Criterion 4: Standard Carveouts
All five of the following carveouts must be present for GREEN classification.
The Five Required Carveouts
| # | Carveout | Standard Language | Why Required |
|---|---|---|---|
| 1 | Public Knowledge | "Information that is or becomes publicly available through no fault of the receiving party" | Cannot restrict public information |
| 2 | Prior Possession | "Information that was already known to the receiving party prior to disclosure, as documented by written records" | Protects pre-existing knowledge |
| 3 | Independent Development | "Information independently developed by the receiving party without use of or reference to the confidential information" | Protects internal R&D and innovation |
| 4 | Third-Party Receipt | "Information received from a third party who is not under a confidentiality obligation to the disclosing party" | Cannot restrict information freely available from others |
| 5 | Legal Compulsion | "Information required to be disclosed by law, regulation, court order, or governmental authority, provided the receiving party gives prompt notice" | Cannot violate legal obligations |
Missing Carveout Impact
| Missing Carveout | Risk Level | Impact |
|---|---|---|
| Public Knowledge | YELLOW | May be implied by law, but should be explicit |
| Prior Possession | YELLOW | Creates risk of contamination claims against pre-existing knowledge |
| Independent Development | YELLOW | Can block entire R&D programs; high-impact for technology companies |
| Third-Party Receipt | YELLOW | Forces due diligence on every piece of information received from third parties |
| Legal Compulsion | YELLOW | May be implied by law, but notice obligation is important |
| Any 3+ missing | RED | Fundamentally deficient NDA; requires comprehensive redline |
Legal Compulsion Sub-Requirements
The legal compulsion carveout should include:
| Element | Standard | Preferred |
|---|---|---|
| Prompt notice to discloser | Required | "Promptly, and in any event prior to disclosure" |
| Cooperation with protective order | Recommended | "Cooperate with efforts to obtain protective order" |
| Minimize scope of disclosure | Recommended | "Disclose only the minimum amount required" |
| Waiver if notice impossible | Recommended | "If notice is prohibited by law, waived" |
---
Criterion 5: Permitted Disclosures
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Representatives | Employees, officers, directors with need-to-know | No specification of who may receive |
| Advisors | Legal counsel, accountants, financial advisors | Advisors excluded from permitted recipients |
| Affiliates | Subsidiaries and parent companies | Affiliates excluded (may need cross-entity sharing) |
| Need-to-Know | Requirement that recipients have a need-to-know | No need-to-know filter |
| Downstream Obligations | Recipients bound by confidentiality | No downstream binding requirement |
---
Criterion 6: Term and Duration
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Agreement Term | 2-5 years | Perpetual or >10 years |
| Survival Period | 2-3 years after termination | No survival or perpetual survival |
| Termination Right | Either party with 30-60 day notice | No termination right |
| Early Termination | For cause or convenience | No early termination option |
Term Ranges
| Duration | Classification | Typical Context |
|---|---|---|
| 1-2 years | GREEN | Short-term project evaluations |
| 2-5 years | GREEN | Standard business relationships |
| 5-7 years | YELLOW | Long-term partnerships; acceptable with justification |
| 7+ years | YELLOW/RED | Unusual; requires justification |
| Perpetual | RED | Unacceptable unless trade secret protection with termination right |
Survival Period Ranges
| Survival | Classification | Notes |
|---|---|---|
| 1-2 years | GREEN | Minimum acceptable |
| 2-3 years | GREEN | Market standard |
| 3-5 years | GREEN | Common for sensitive information |
| 5+ years | YELLOW | May be appropriate for trade secrets |
| Perpetual | YELLOW/RED | Acceptable only for trade secrets with clear definition |
---
Criterion 7: Return and Destruction
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Trigger | Upon request or termination | No trigger specified |
| Options | Return or destroy, at receiving party's election | Only return (may be impractical for electronic data) |
| Timeline | Within 30 days of request | No timeline or unreasonably short (e.g., 24 hours) |
| Certification | Written certification of destruction | No certification required |
| Retention Exception | May retain copies required by law or internal backup policy | No retention exception (impractical for automated backups) |
---
Criterion 8: Remedies
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Injunctive Relief | Available without bond | No mention of equitable remedies |
| Damages | Standard breach-of-contract damages | Liquidated damages or penalty clauses |
| Indemnification | Not standard in NDAs | Broad indemnification obligation |
| Limitation of Liability | Not standard in NDAs | Unlimited liability for breach |
| Prevailing Party Fees | Optional; acceptable either way | Mandatory fee-shifting in one direction only |
Remedy Red Flags
| Provision | Severity | Why Problematic |
|---|---|---|
| Liquidated damages ($X per breach) | RED | Transforms NDA into penalty contract; disproportionate to actual harm |
| Unlimited liability for breach | YELLOW | Standard NDAs rely on actual damages; uncapped exposure is excessive |
| One-way indemnification | YELLOW | Shifts all risk to one party; inappropriate for a confidentiality agreement |
| Specific performance mandated | GREEN | Standard and appropriate for confidentiality obligations |
---
Criterion 9: Problematic Provisions
These provisions are NOT standard in NDAs and should trigger escalation.
Provision Risk Classification
| Provision | Severity | Description | Standard Position |
|---|---|---|---|
| Non-Solicitation | RED | Restricts hiring or soliciting employees/customers | Remove entirely; not appropriate for NDA |
| Non-Compete | RED | Restricts competitive business activities | Remove entirely; requires separate agreement |
| Exclusivity | RED | Limits engagement with other parties | Remove entirely; NDA is not an exclusivity agreement |
| IP Assignment | RED | Transfers intellectual property rights | Remove entirely; NDA protects information, not transfers IP |
| Broad License Grant | RED | Grants license to use confidential information | Remove entirely; conflicts with purpose of NDA |
| Liquidated Damages | RED | Pre-determined penalty for breach | Remove; rely on standard breach remedies |
| Residuals Clause | YELLOW | Allows use of ideas retained in unaided memory | Remove or narrow to exclude trade secrets explicitly |
| Audit Rights | YELLOW | Allows inspection of premises or systems | Remove or limit to annual with notice |
| Standstill Provision | YELLOW | Restricts acquisition activities | Flag for M&A counsel; may be appropriate in some contexts |
Residuals Clause Deep Dive
A residuals clause typically allows a party to use "general ideas, concepts, know-how, and techniques" retained in the "unaided memory" of individuals who had access to confidential information.
Why it is problematic:
- Effectively creates a carveout that swallows the NDA protection
- Difficult to prove what was "retained in unaided memory" vs. what was memorized deliberately
- Can be used to justify use of trade secrets
Standard position: Remove the residuals clause entirely. If counterparty insists, narrow it to:
- Exclude trade secrets explicitly
- Require that individuals did not intentionally memorize information
- Limit to general concepts, not specific data points or algorithms
---
Criterion 10: Governing Law
What to Check
| Sub-Item | Standard | Red Flag |
|---|---|---|
| Governing Law | Specified and acceptable | No governing law or hostile jurisdiction |
| Jurisdiction | Courts identified | No jurisdiction specified |
| Dispute Resolution | Litigation or arbitration specified | No dispute resolution mechanism |
| Venue | Specific venue identified | Inconvenient venue |
Jurisdiction Preference Tiers
| Tier | Jurisdictions | Notes |
|---|---|---|
| Preferred | Home state/country of your entity | Best: familiar law, local counsel, convenient |
| Acceptable | Delaware, New York, England, Singapore | Neutral, well-developed commercial law |
| Review Required | Other US states, EU member states | May be acceptable; requires counsel assessment |
| Escalate | Non-Western jurisdictions, unfamiliar legal systems | Requires senior counsel review |
---
Common NDA Issues and Redline Approaches
| Issue | Detection Signal | Redline Approach | Fallback |
|---|---|---|---|
| Overbroad definition | "All information of any kind" | Narrow to information marked or identified as confidential | Add marking requirement with 10-day oral confirmation window |
| Missing independent development carveout | Absent from exclusions section | Add standard carveout language | At minimum: "independently developed without use of Confidential Information as demonstrated by documentary evidence" |
| Non-solicitation clause | "Shall not solicit" employees or customers | Delete entire provision | If counterparty insists: limit to direct solicitation of specific named individuals for 12 months |
| Broad residuals clause | "Unaided memory" with no limitations | Delete entirely | Narrow: exclude trade secrets, require non-intentional retention, limit to general concepts |
| Perpetual obligations | "In perpetuity" or no term specified | Add 3-year term with 2-year survival | Accept 5-year term with 3-year survival |
| No return/destruction | Absent from agreement | Add return or destroy within 30 days of request/termination | Accept retention exception for legal and backup copies with continued confidentiality |
| IP assignment in NDA | "Assigns all right, title, interest" | Delete entirely; NDA is not an IP agreement | If counterparty insists: this is a fundamental scope issue requiring separate negotiation |
| One-sided obligations in "mutual" NDA | Mutual header but only one party obligated | Revise to make obligations truly mutual | Accept one-way structure if appropriate, but relabel accurately |
| No legal compulsion notice | Legal compulsion carveout without notice requirement | Add: "Shall provide prompt written notice prior to disclosure" | Add: "Shall provide notice to the extent legally permitted" |
| Missing effective date | No date on agreement | Add effective date provision | Use "date of last signature" as effective date |
#!/usr/bin/env python3
"""
NDA Checklist Generator
Generates a 10-point compliance checklist for an NDA, checking all
screening criteria with pass/fail status and notes.
Usage:
python nda_checklist.py nda_draft.txt
python nda_checklist.py nda_draft.txt --json
python nda_checklist.py nda_draft.txt --output checklist.json --json
"""
import argparse
import json
import os
import re
import sys
from typing import Dict, List, Tuple
# 10-point screening criteria with detection patterns
SCREENING_CRITERIA = [
{
"id": 1,
"name": "Agreement Structure",
"description": "Mutual vs. one-way; parties identified; purpose stated",
"checks": [
{
"name": "parties_identified",
"patterns": [
r"between\s+.{2,60}\s+(?:and|&)\s+.{2,60}",
r"(?:party|parties)\s+(?:hereto|to\s+this)",
r"(?:\"company\"|\"discloser\"|\"recipient\"|\"party\s+[ab]\")",
],
"description": "Parties clearly identified",
},
{
"name": "purpose_stated",
"patterns": [
r"(?:purpose|reason|connection\s+with|in\s+relation\s+to|regarding)\s+(?:of|for)?\s*(?:this|the)\s+(?:agreement|nda|disclosure)",
r"(?:evaluat|explor|discuss|consider|assess|pursu)",
r"(?:business\s+(?:purpose|relationship|opportunity|transaction))",
],
"description": "Purpose of disclosure stated",
},
{
"name": "mutual_or_one_way",
"patterns": [
r"mutual",
r"(?:each|both)\s+part(?:y|ies)",
r"(?:one[- ]?way|unilateral)",
r"(?:disclosing\s+party|receiving\s+party)",
],
"description": "Direction of obligations clear (mutual or one-way)",
},
],
},
{
"id": 2,
"name": "Definition of Confidential Information",
"description": "Scope, specificity, marking requirements",
"checks": [
{
"name": "definition_present",
"patterns": [
r"(?:\"|')confidential\s+information(?:\"|')\s+(?:means|shall\s+mean|includes?|refers?\s+to)",
r"(?:definition|meaning)\s+of\s+confidential",
r"confidential\s+information\s+(?:is\s+defined|means)",
],
"description": "Confidential information defined",
},
{
"name": "marking_requirement",
"patterns": [
r"mark(?:ed|ing)\s+(?:as\s+)?(?:\"|')?\s*confidential",
r"(?:labeled|designated|stamped)\s+(?:as\s+)?confidential",
r"(?:written|oral).*(?:confirm|identif|summariz).*(?:in\s+writing|\d+\s+(?:day|business))",
],
"description": "Marking or identification requirement for confidential information",
},
{
"name": "scope_bounded",
"patterns": [
r"(?:relating\s+to|concerning|regarding|in\s+connection\s+with)\s+(?:the\s+)?(?:purpose|project|transaction|business)",
r"limited\s+to",
r"specifically\s+(?:identified|designated|marked)",
],
"description": "Scope of confidential information is bounded",
},
],
},
{
"id": 3,
"name": "Obligations",
"description": "Standard of care, use restrictions, disclosure limits",
"checks": [
{
"name": "standard_of_care",
"patterns": [
r"reasonable\s+(?:care|efforts?|measures?|steps?|precautions?)",
r"same\s+(?:degree|standard|level)\s+of\s+(?:care|protection)",
r"protect.*(?:confidential|proprietary).*(?:reasonable|same\s+degree)",
],
"description": "Standard of care for protecting confidential information",
},
{
"name": "use_restriction",
"patterns": [
r"(?:use|utilized?)\s+(?:solely|only|exclusively)\s+(?:for|in\s+connection)",
r"shall\s+not\s+(?:use|utilize)\s+(?:the\s+)?confidential.*(?:except|other\s+than)",
r"(?:restricted|limited)\s+(?:to\s+)?(?:the\s+)?(?:purpose|permitted\s+use)",
],
"description": "Use restricted to stated purpose",
},
{
"name": "disclosure_limits",
"patterns": [
r"shall\s+not\s+(?:disclose|reveal|divulge|share)",
r"(?:restrict|limit)\s+(?:disclosure|access)\s+to",
r"need[- ]to[- ]know\s+basis",
],
"description": "Disclosure limited to authorized persons",
},
],
},
{
"id": 4,
"name": "Standard Carveouts",
"description": "5 required: public knowledge, prior possession, independent development, third-party receipt, legal compulsion",
"checks": [
{
"name": "public_knowledge",
"patterns": [
r"public(?:ly)?\s+(?:known|available|domain)",
r"generally\s+(?:known|available)\s+to\s+the\s+public",
],
"description": "Public knowledge carveout",
},
{
"name": "prior_possession",
"patterns": [
r"prior\s+(?:possession|knowledge|receipt)",
r"already\s+(?:known|possessed|in\s+possession)",
],
"description": "Prior possession carveout",
},
{
"name": "independent_development",
"patterns": [
r"independent(?:ly)?\s+develop",
r"without\s+(?:use\s+of|reference\s+to)\s+(?:the\s+)?confidential",
],
"description": "Independent development carveout",
},
{
"name": "third_party_receipt",
"patterns": [
r"(?:received|obtained)\s+from\s+a\s+third\s+party",
r"third[- ]party\s+(?:source|disclosure)",
],
"description": "Third-party receipt carveout",
},
{
"name": "legal_compulsion",
"patterns": [
r"(?:required|compelled|ordered)\s+(?:by|under)\s+law",
r"court\s+order",
r"subpoena",
r"legal(?:ly)?\s+(?:required|compelled)",
],
"description": "Legal compulsion carveout",
},
],
},
{
"id": 5,
"name": "Permitted Disclosures",
"description": "Representatives, advisors, affiliates with need-to-know",
"checks": [
{
"name": "representatives",
"patterns": [
r"(?:representatives?|employees?|officers?|directors?)",
r"(?:agents?|advisors?|counsel|accountants?|consultants?)",
],
"description": "Disclosure to representatives permitted",
},
{
"name": "need_to_know",
"patterns": [
r"need[- ]to[- ]know",
r"(?:require|necessary)\s+(?:for\s+)?(?:the\s+)?(?:purpose|performance)",
],
"description": "Need-to-know requirement for permitted recipients",
},
{
"name": "affiliate_coverage",
"patterns": [
r"affiliates?",
r"subsidi(?:ary|aries)",
r"(?:parent|related)\s+(?:compan|entit)",
],
"description": "Affiliates covered in permitted disclosures",
},
],
},
{
"id": 6,
"name": "Term & Duration",
"description": "Reasonable term, survival period, obligations after expiry",
"checks": [
{
"name": "term_defined",
"patterns": [
r"term\s+(?:of\s+)?(?:this\s+)?(?:agreement\s+)?(?:shall\s+be|is)\s+\d",
r"\d+\s+(?:year|month)s?\s+(?:from|after|following)",
r"(?:effective|initial)\s+(?:date|period|term)",
],
"description": "Agreement term is defined",
},
{
"name": "survival_period",
"patterns": [
r"surviv(?:e|al|ing).*(?:\d+\s+(?:year|month)|termination|expir)",
r"(?:obligations?|duties?)\s+(?:shall\s+)?(?:survive|continue)\s+(?:for\s+)?\d+",
r"(?:after|following)\s+(?:termination|expir).*\d+\s+(?:year|month)",
],
"description": "Survival period for obligations after termination",
},
],
},
{
"id": 7,
"name": "Return/Destruction",
"description": "Obligation to return or destroy upon request or termination",
"checks": [
{
"name": "return_or_destroy",
"patterns": [
r"return\s+(?:or\s+)?destroy",
r"destroy\s+(?:or\s+)?return",
r"(?:return|destruction)\s+of\s+(?:all\s+)?(?:confidential\s+)?(?:information|materials|copies|documents)",
],
"description": "Return or destruction obligation present",
},
{
"name": "certification",
"patterns": [
r"certif(?:y|ication)\s+(?:of\s+)?(?:destruction|compliance|return)",
r"(?:written|officer)\s+certif",
],
"description": "Certification of destruction required",
},
],
},
{
"id": 8,
"name": "Remedies",
"description": "Injunctive relief, damages, indemnification scope",
"checks": [
{
"name": "injunctive_relief",
"patterns": [
r"injunctive\s+relief",
r"specific\s+performance",
r"equitable\s+(?:relief|remed)",
r"irreparable\s+(?:harm|injury|damage)",
],
"description": "Injunctive relief available for breach",
},
{
"name": "no_liquidated_damages",
"patterns": [
r"liquidated\s+damages",
r"stipulated\s+damages",
r"penalty\s+(?:of|in\s+the\s+amount)",
],
"description": "No liquidated damages (negative check)",
"negative": True,
},
],
},
{
"id": 9,
"name": "Problematic Provisions",
"description": "Non-solicitation, non-compete, exclusivity, residuals, IP assignment, audit rights",
"checks": [
{
"name": "no_non_solicitation",
"patterns": [r"non[- ]?solicitation", r"shall\s+not\s+solicit"],
"description": "No non-solicitation clause",
"negative": True,
},
{
"name": "no_non_compete",
"patterns": [r"non[- ]?compete", r"competitive\s+activit", r"shall\s+not\s+compete"],
"description": "No non-compete clause",
"negative": True,
},
{
"name": "no_exclusivity",
"patterns": [r"exclusiv(?:e|ity)\s+(?:deal|negotiat|discuss|period|obligation)"],
"description": "No exclusivity provision",
"negative": True,
},
{
"name": "no_ip_assignment",
"patterns": [r"assign(?:s|ment)?\s+(?:all\s+)?(?:right|title)", r"work[- ]?for[- ]?hire"],
"description": "No IP assignment clause",
"negative": True,
},
{
"name": "no_residuals",
"patterns": [r"residual", r"unaided\s+(?:memory|recall)"],
"description": "No residuals clause",
"negative": True,
},
],
},
{
"id": 10,
"name": "Governing Law",
"description": "Jurisdiction, dispute resolution mechanism",
"checks": [
{
"name": "governing_law",
"patterns": [
r"govern(?:ed|ing)\s+(?:by\s+)?(?:the\s+)?laws?\s+of",
r"applicable\s+law",
r"choice\s+of\s+law",
],
"description": "Governing law specified",
},
{
"name": "dispute_resolution",
"patterns": [
r"(?:dispute|controversy)\s+(?:resolution|settlement)",
r"arbitration",
r"jurisdiction\s+of\s+(?:the\s+)?courts?",
r"(?:venue|forum)\s+(?:for\s+)?(?:any\s+)?(?:dispute|action|proceeding)",
],
"description": "Dispute resolution mechanism specified",
},
],
},
]
def read_nda(file_path: str) -> str:
"""Read NDA text from file."""
if not os.path.isfile(file_path):
print(f"Error: File not found: {file_path}", file=sys.stderr)
sys.exit(1)
try:
with open(file_path, "r", encoding="utf-8") as f:
return f.read()
except UnicodeDecodeError:
with open(file_path, "r", encoding="latin-1") as f:
return f.read()
def evaluate_criterion(text: str, criterion: Dict) -> Dict:
"""Evaluate a single screening criterion against NDA text."""
text_lower = text.lower()
checks_results = []
all_pass = True
critical_fail = False
for check in criterion["checks"]:
found = False
for pattern in check["patterns"]:
if re.search(pattern, text_lower):
found = True
break
is_negative = check.get("negative", False)
if is_negative:
# For negative checks, finding the pattern means FAIL
passed = not found
if not passed:
critical_fail = True
else:
# For positive checks, finding the pattern means PASS
passed = found
if not passed:
all_pass = False
checks_results.append({
"name": check["name"],
"description": check["description"],
"passed": passed,
"negative_check": is_negative,
})
# Determine overall status for this criterion
if critical_fail:
status = "FAIL"
elif all_pass:
status = "PASS"
else:
# Partial pass: at least one sub-check failed but no critical failures
passed_count = sum(1 for c in checks_results if c["passed"])
total_count = len(checks_results)
if passed_count >= total_count / 2:
status = "PARTIAL"
else:
status = "FAIL"
# Generate notes
notes_parts = []
for cr in checks_results:
if not cr["passed"]:
if cr["negative_check"]:
notes_parts.append(f"Detected: {cr['description'].replace('No ', '')}")
else:
notes_parts.append(f"Missing: {cr['description']}")
notes = "; ".join(notes_parts) if notes_parts else "All checks passed"
return {
"id": criterion["id"],
"name": criterion["name"],
"description": criterion["description"],
"status": status,
"notes": notes,
"checks": checks_results,
}
def classify_from_checklist(results: List[Dict]) -> Tuple[str, int, int]:
"""Classify NDA based on checklist results."""
pass_count = sum(1 for r in results if r["status"] == "PASS")
fail_count = sum(1 for r in results if r["status"] == "FAIL")
total = len(results)
# Check for critical failures
critical_criteria = [4, 9] # Standard Carveouts and Problematic Provisions
critical_fails = [r for r in results if r["id"] in critical_criteria and r["status"] == "FAIL"]
if critical_fails or fail_count >= 3:
return "RED", pass_count, total
elif fail_count >= 1 or any(r["status"] == "PARTIAL" for r in results):
return "YELLOW", pass_count, total
else:
return "GREEN", pass_count, total
def format_text_output(result: Dict) -> str:
"""Format checklist as human-readable text."""
lines = []
lines.append("NDA COMPLIANCE CHECKLIST")
lines.append("=" * 50)
lines.append(f"File: {result['file']}")
lines.append(f"Overall: {result['classification']} ({result['pass_count']}/{result['total']} PASS)")
lines.append("")
# Header
lines.append(f" {'#':>2} {'Criterion':<32} {'Status':<8} Notes")
lines.append(f" {'--':>2} {'-' * 32} {'-' * 8} {'-' * 40}")
for criterion in result["criteria"]:
status_display = criterion["status"]
lines.append(
f" {criterion['id']:>2} {criterion['name']:<32} {status_display:<8} {criterion['notes']}"
)
lines.append("")
# Failed criteria details
failed = [c for c in result["criteria"] if c["status"] in ("FAIL", "PARTIAL")]
if failed:
lines.append("DETAILS ON FAILED/PARTIAL CRITERIA")
lines.append("-" * 40)
for criterion in failed:
lines.append(f" [{criterion['status']}] #{criterion['id']} {criterion['name']}")
for check in criterion["checks"]:
if not check["passed"]:
prefix = " [!]" if check.get("negative_check") else " [-]"
lines.append(f" {prefix} {check['description']}")
lines.append("")
return "\n".join(lines)
def generate_checklist(file_path: str) -> Dict:
"""Main checklist generation pipeline."""
text = read_nda(file_path)
results = []
for criterion in SCREENING_CRITERIA:
result = evaluate_criterion(text, criterion)
results.append(result)
classification, pass_count, total = classify_from_checklist(results)
return {
"file": os.path.basename(file_path),
"classification": classification,
"pass_count": pass_count,
"total": total,
"criteria": results,
}
def main():
parser = argparse.ArgumentParser(
description="Generate a 10-point compliance checklist for an NDA."
)
parser.add_argument("nda_file", help="Path to NDA text file (.txt or .md)")
parser.add_argument("--json", action="store_true", dest="json_output",
help="Output in JSON format")
parser.add_argument("-o", "--output", help="Write output to file")
args = parser.parse_args()
result = generate_checklist(args.nda_file)
if args.json_output:
output = json.dumps(result, indent=2)
else:
output = format_text_output(result)
if args.output:
try:
with open(args.output, "w", encoding="utf-8") as f:
f.write(output)
print(f"Output written to {args.output}")
except IOError as e:
print(f"Error writing to {args.output}: {e}", file=sys.stderr)
sys.exit(1)
else:
print(output)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
NDA Screener
Scans NDA text for red flags, missing carveouts, and problematic provisions.
Outputs GREEN/YELLOW/RED classification with reasoning.
Usage:
python nda_screener.py nda_draft.txt
python nda_screener.py incoming_nda.md --json
python nda_screener.py nda_draft.txt --output screening.json --json
"""
import argparse
import json
import os
import re
import sys
from typing import Dict, List, Tuple
# Standard carveouts that should be present in every NDA
STANDARD_CARVEOUTS = {
"public_knowledge": {
"patterns": [
r"public(?:ly)?\s+(?:known|available|domain)",
r"generally\s+(?:known|available)\s+to\s+the\s+public",
r"becomes?\s+public(?:ly)?\s+(?:known|available)",
r"part\s+of\s+the\s+public\s+domain",
r"public\s+knowledge",
],
"description": "Information that is or becomes publicly available",
},
"prior_possession": {
"patterns": [
r"prior\s+(?:possession|knowledge|receipt)",
r"already\s+(?:known|possessed|in\s+possession)",
r"(?:known|possessed)\s+(?:by|to)\s+the\s+receiving",
r"in\s+(?:its|the)\s+possession\s+prior",
r"previously\s+known",
],
"description": "Information already known to the receiving party before disclosure",
},
"independent_development": {
"patterns": [
r"independent(?:ly)?\s+develop",
r"developed\s+independent(?:ly)?",
r"without\s+(?:use\s+of|reference\s+to|reliance\s+on)\s+(?:the\s+)?confidential",
r"independent\s+creation",
],
"description": "Information independently developed without use of confidential information",
},
"third_party_receipt": {
"patterns": [
r"(?:received|obtained)\s+from\s+a\s+third\s+party",
r"third[- ]party\s+(?:source|disclosure|receipt)",
r"lawfully\s+(?:received|obtained|acquired)\s+from",
r"rightfully\s+(?:received|obtained)\s+from",
],
"description": "Information received from a third party without confidentiality obligation",
},
"legal_compulsion": {
"patterns": [
r"(?:required|compelled|ordered)\s+(?:by|under|pursuant\s+to)\s+law",
r"legal(?:ly)?\s+(?:required|compelled|obligated)",
r"court\s+order",
r"subpoena",
r"government(?:al)?\s+(?:request|order|requirement)",
r"judicial\s+(?:order|process|proceeding)",
r"regulatory\s+(?:requirement|authority|request)",
],
"description": "Disclosure required by law, court order, or governmental authority",
},
}
# Problematic provisions to flag
RED_FLAG_PROVISIONS = [
{
"id": "non_solicitation",
"patterns": [
r"non[- ]?solicitation",
r"shall\s+not\s+solicit",
r"refrain\s+from\s+soliciting",
r"not\s+(?:directly\s+or\s+indirectly\s+)?solicit",
],
"severity": "RED",
"description": "Non-solicitation clause restricting hiring or business solicitation",
"recommendation": "Remove non-solicitation clause; it is not standard in NDAs",
},
{
"id": "non_compete",
"patterns": [
r"non[- ]?compete",
r"shall\s+not\s+compete",
r"competitive\s+activit",
r"not\s+engage\s+in\s+(?:any\s+)?(?:business|activit)",
r"refrain\s+from\s+compet",
],
"severity": "RED",
"description": "Non-compete clause restricting business activities",
"recommendation": "Remove non-compete clause; unacceptable in a standard NDA",
},
{
"id": "exclusivity",
"patterns": [
r"exclusive(?:ly)?\s+(?:deal|negotiate|discuss|engage)",
r"exclusivity\s+(?:period|obligation|provision)",
r"shall\s+not\s+(?:discuss|negotiate|engage)\s+with\s+(?:any\s+)?(?:other|third)",
],
"severity": "RED",
"description": "Exclusivity provision limiting engagement with other parties",
"recommendation": "Remove exclusivity clause; inappropriate for an NDA",
},
{
"id": "residuals",
"patterns": [
r"residual(?:s)?\s+(?:clause|knowledge|information|rights)",
r"unaided\s+(?:memory|recall|recollection)",
r"retained\s+in\s+(?:the\s+)?(?:unaided\s+)?memor",
r"general\s+(?:knowledge|skills|experience)\s+retained",
],
"severity": "YELLOW",
"description": "Residuals clause allowing use of ideas retained in memory",
"recommendation": "Remove or narrowly scope residuals clause to exclude trade secrets",
},
{
"id": "ip_assignment",
"patterns": [
r"assign(?:s|ment)?\s+(?:all\s+)?(?:right|title|interest)\s+in",
r"(?:intellectual\s+property|ip)\s+(?:rights?\s+)?(?:shall\s+)?(?:be\s+)?(?:owned\s+by|vest\s+in|transfer)",
r"work[- ]?(?:for[- ]?hire|made\s+for\s+hire)",
r"hereby\s+assign",
],
"severity": "RED",
"description": "IP assignment or work-for-hire clause in an NDA",
"recommendation": "Remove IP assignment; NDAs should not transfer IP rights",
},
{
"id": "ip_license_grant",
"patterns": [
r"grant(?:s)?\s+(?:a\s+)?(?:non-exclusive|exclusive|perpetual|irrevocable)\s+license",
r"license\s+to\s+use.*confidential\s+information",
r"right\s+to\s+(?:use|exploit|commercialize)",
],
"severity": "RED",
"description": "License grant over confidential information",
"recommendation": "Remove license grant; NDA should protect information, not license it",
},
{
"id": "liquidated_damages",
"patterns": [
r"liquidated\s+damages",
r"stipulated\s+damages",
r"pre[- ]?determined\s+damages",
r"penalty\s+(?:of|in\s+the\s+amount)",
r"\$[\d,]+\s+(?:per|for\s+each)\s+(?:breach|violation)",
],
"severity": "RED",
"description": "Liquidated damages or penalty provision for breach",
"recommendation": "Remove liquidated damages; standard remedies are sufficient for NDAs",
},
{
"id": "unlimited_audit",
"patterns": [
r"(?:unlimited|unrestricted)\s+(?:audit|inspection|access)",
r"audit\s+(?:at\s+any\s+time|without\s+(?:notice|limitation))",
r"right\s+to\s+inspect.*(?:premises|records|systems)",
],
"severity": "YELLOW",
"description": "Audit rights allowing inspection of premises or systems",
"recommendation": "Remove or limit audit rights; excessive for standard NDAs",
},
{
"id": "perpetual_obligations",
"patterns": [
r"perpetual(?:ly)?\s+(?:confidential|obligat)",
r"obligations?\s+(?:shall\s+)?(?:survive|continue)\s+(?:in\s+)?perpetuit",
r"indefinite(?:ly)?\s+(?:period|term|duration|obligat)",
r"no\s+expiration\s+(?:of\s+)?(?:confidentiality|obligations)",
r"forever\s+(?:remain|be\s+kept|maintain)",
],
"severity": "YELLOW",
"description": "Perpetual or indefinite confidentiality obligations",
"recommendation": "Limit obligations to 3-5 years from disclosure or termination",
},
{
"id": "overbroad_definition",
"patterns": [
r"all\s+information\s+(?:of\s+any\s+(?:kind|nature|type)|whatsoever|disclosed)",
r"any\s+(?:and\s+all\s+)?information\s+(?:relating\s+to|concerning|regarding)\s+(?:the\s+)?(?:disclos|party)",
r"without\s+limitation.*(?:oral|written|visual|electronic|any\s+(?:form|medium))",
],
"severity": "YELLOW",
"description": "Overbroad definition of confidential information",
"recommendation": "Narrow definition to information marked confidential or reasonably understood to be confidential",
},
{
"id": "one_sided_obligations",
"patterns": [
r"(?:only|solely)\s+(?:the\s+)?(?:receiving|recipient)\s+(?:party\s+)?(?:shall|agrees?|is\s+obligated)",
r"(?:disclos(?:ing|er)|provider)\s+(?:party\s+)?(?:shall\s+have\s+no|is\s+not\s+(?:subject|bound))",
],
"severity": "YELLOW",
"description": "One-sided obligations (only binding on receiving party)",
"recommendation": "Request mutual obligations or ensure one-way structure is appropriate for the relationship",
},
]
# Structure detection patterns
STRUCTURE_PATTERNS = {
"mutual": [
r"mutual\s+(?:non[- ]?disclosure|nda|confidentiality)",
r"each\s+party\s+(?:may\s+)?disclos",
r"(?:both|each)\s+parties?\s+(?:shall|agree)",
r"disclosing\s+party.*receiving\s+party",
],
"one_way": [
r"(?:one[- ]?way|unilateral)\s+(?:non[- ]?disclosure|nda|confidentiality)",
r"(?:the\s+)?(?:company|discloser)\s+(?:may\s+)?disclose.*(?:the\s+)?(?:recipient|receiver)\s+(?:shall|agrees?)",
],
"return_destruction": [
r"return\s+(?:or\s+)?destroy",
r"destroy\s+(?:or\s+)?return",
r"(?:return|destruction)\s+of\s+(?:confidential\s+)?(?:information|materials)",
r"certif(?:y|ication)\s+of\s+destruction",
],
"injunctive_relief": [
r"injunctive\s+relief",
r"specific\s+performance",
r"equitable\s+relief",
r"irreparable\s+(?:harm|injury|damage)",
],
"term_defined": [
r"(?:initial\s+)?term\s+(?:of\s+)?(?:this\s+)?(?:agreement\s+)?(?:shall\s+be|is)\s+\d",
r"\d+\s+(?:year|month|day)s?\s+(?:from|after|following)",
r"effective\s+(?:date|period).*(?:terminat|expir)",
],
"governing_law": [
r"govern(?:ed|ing)\s+(?:by\s+)?(?:the\s+)?laws?\s+of",
r"(?:state|commonwealth)\s+of\s+\w+",
r"jurisdiction\s+of\s+(?:the\s+)?courts?",
],
"permitted_disclosures": [
r"permitted\s+disclos",
r"(?:representatives?|advisors?|agents?|employees?|officers?|directors?)\s+(?:who\s+)?(?:have\s+a\s+)?need[- ]to[- ]know",
r"disclose\s+to\s+(?:its\s+)?(?:representatives?|advisors?|counsel|accountants?)",
],
}
def read_nda(file_path: str) -> str:
"""Read NDA text from file."""
if not os.path.isfile(file_path):
print(f"Error: File not found: {file_path}", file=sys.stderr)
sys.exit(1)
try:
with open(file_path, "r", encoding="utf-8") as f:
return f.read()
except UnicodeDecodeError:
with open(file_path, "r", encoding="latin-1") as f:
return f.read()
def check_carveouts(text: str) -> Dict[str, bool]:
"""Check which standard carveouts are present."""
text_lower = text.lower()
results = {}
for carveout_id, carveout_def in STANDARD_CARVEOUTS.items():
found = False
for pattern in carveout_def["patterns"]:
if re.search(pattern, text_lower):
found = True
break
results[carveout_id] = found
return results
def detect_red_flags(text: str) -> List[Dict]:
"""Detect problematic provisions in NDA text."""
text_lower = text.lower()
flags: List[Dict] = []
for provision in RED_FLAG_PROVISIONS:
for pattern in provision["patterns"]:
match = re.search(pattern, text_lower)
if match:
# Extract context around the match
start = max(0, match.start() - 50)
end = min(len(text_lower), match.end() + 50)
context = text[start:end].strip().replace("\n", " ")
flags.append({
"id": provision["id"],
"severity": provision["severity"],
"description": provision["description"],
"recommendation": provision["recommendation"],
"context": context[:200],
})
break # One match per provision
return flags
def detect_structure(text: str) -> Dict[str, bool]:
"""Detect structural elements of the NDA."""
text_lower = text.lower()
results = {}
for element, patterns in STRUCTURE_PATTERNS.items():
found = False
for pattern in patterns:
if re.search(pattern, text_lower):
found = True
break
results[element] = found
return results
def classify_nda(carveouts: Dict[str, bool], red_flags: List[Dict],
structure: Dict[str, bool]) -> Tuple[str, str]:
"""Classify NDA as GREEN/YELLOW/RED with reasoning."""
reasons: List[str] = []
# Count issues
missing_carveouts = [k for k, v in carveouts.items() if not v]
red_severity_flags = [f for f in red_flags if f["severity"] == "RED"]
yellow_severity_flags = [f for f in red_flags if f["severity"] == "YELLOW"]
# RED classification triggers
if len(missing_carveouts) >= 3:
reasons.append(f"{len(missing_carveouts)} missing standard carveouts")
if red_severity_flags:
flag_names = [f["id"] for f in red_severity_flags]
reasons.append(f"Critical provisions: {', '.join(flag_names)}")
if len(missing_carveouts) >= 3 or red_severity_flags:
summary = "; ".join(reasons) + ". Do not sign without senior counsel review."
return "RED", summary
# YELLOW classification triggers
if missing_carveouts:
carveout_names = [STANDARD_CARVEOUTS[k]["description"] for k in missing_carveouts]
reasons.append(f"Missing carveout(s): {'; '.join(carveout_names)}")
if yellow_severity_flags:
flag_names = [f["description"] for f in yellow_severity_flags]
reasons.append(f"Minor concerns: {'; '.join(flag_names)}")
if not structure.get("mutual") and not structure.get("one_way"):
reasons.append("Agreement structure unclear (mutual vs. one-way)")
if not structure.get("return_destruction"):
reasons.append("No return/destruction obligation detected")
if not structure.get("term_defined"):
reasons.append("No defined term or duration detected")
if reasons:
summary = "; ".join(reasons) + ". Route to counsel for review."
return "YELLOW", summary
# GREEN classification
summary = "All standard carveouts present; no problematic provisions detected. Standard approval."
return "GREEN", summary
def format_text_output(result: Dict) -> str:
"""Format screening results as human-readable text."""
lines = []
lines.append("NDA SCREENING REPORT")
lines.append("=" * 50)
lines.append(f"File: {result['file']}")
lines.append(f"Classification: {result['classification']}")
lines.append(f"Summary: {result['summary']}")
lines.append("")
# Carveouts
lines.append("STANDARD CARVEOUTS")
lines.append("-" * 30)
for carveout_id, present in result["carveouts"].items():
status = "PRESENT" if present else "MISSING"
desc = STANDARD_CARVEOUTS[carveout_id]["description"]
marker = " [+]" if present else " [!]"
lines.append(f"{marker} {desc}: {status}")
lines.append("")
# Structure
lines.append("STRUCTURE")
lines.append("-" * 30)
for element, detected in result["structure"].items():
status = "Yes" if detected else "No"
lines.append(f" {element.replace('_', ' ').title()}: {status}")
lines.append("")
# Red flags
if result["red_flags"]:
lines.append("RED FLAGS")
lines.append("-" * 30)
for flag in result["red_flags"]:
lines.append(f" [{flag['severity']}] {flag['description']}")
lines.append(f" Recommendation: {flag['recommendation']}")
if flag.get("context"):
lines.append(f" Context: ...{flag['context']}...")
lines.append("")
else:
lines.append("RED FLAGS: None detected")
lines.append("")
return "\n".join(lines)
def screen_nda(file_path: str) -> Dict:
"""Main screening pipeline."""
text = read_nda(file_path)
carveouts = check_carveouts(text)
red_flags = detect_red_flags(text)
structure = detect_structure(text)
classification, summary = classify_nda(carveouts, red_flags, structure)
return {
"file": os.path.basename(file_path),
"classification": classification,
"summary": summary,
"carveouts": carveouts,
"red_flags": red_flags,
"structure": structure,
}
def main():
parser = argparse.ArgumentParser(
description="Screen NDA text for red flags and classify as GREEN/YELLOW/RED."
)
parser.add_argument("nda_file", help="Path to NDA text file (.txt or .md)")
parser.add_argument("--json", action="store_true", dest="json_output",
help="Output in JSON format")
parser.add_argument("-o", "--output", help="Write output to file")
args = parser.parse_args()
result = screen_nda(args.nda_file)
if args.json_output:
output = json.dumps(result, indent=2)
else:
output = format_text_output(result)
if args.output:
try:
with open(args.output, "w", encoding="utf-8") as f:
f.write(output)
print(f"Output written to {args.output}")
except IOError as e:
print(f"Error writing to {args.output}: {e}", file=sys.stderr)
sys.exit(1)
else:
print(output)
if __name__ == "__main__":
main()
Related skills
FAQ
How does nda-triage classify an NDA?
It outputs GREEN (business approval), YELLOW (counsel review within 48 hours), or RED (senior counsel; do not sign).
What are the 5 standard carveouts it checks?
Public knowledge, prior possession, independent development, third-party receipt, and legal compulsion.