Contract Redline LangGraph
What it does
A reader opens the contract from the drive and extracts its clauses. A redliner proposes edits that move off-standard terms toward the company's negotiation playbook (read from disk), and a reviewer checks each edit against that playbook and flags residual risk. The two loop until the reviewer signs off or the round budget is reached. A risk memo is produced and the package pauses for a human lawyer to approve before it is shared. Replace the playbook file with your own standard positions.
The cast · 4 agents
Open the contract and extract its clauses: label each by type (liability, term, indemnity, IP, payment, etc.) and capture its exact text. Do not judge yet.
Read the negotiation playbook from disk. Propose the minimal edits that bring off-standard clauses in line with it, quoting the exact replacement text. If you received a review, address every flag and try again. Never soften a position the playbook marks non-negotiable.
Check the redline against the playbook. Flag any clause still off-standard, any edit that overreaches, and any risk a counterparty would reject. Return an object with a 'clean' boolean and specific notes. Sign off only when the redline is defensible and complete.
Write a short risk memo for the reviewing lawyer: what was changed, what still carries risk, and what to watch in negotiation. Post a pointer to the legal channel. Do not send anything to the counterparty.
Flow
Interface
Depends on · 3 MCP servers
Multi-account MCP for Gmail, Calendar, Drive, Docs, and Sheets — 61 tools, tokenio.github.adelaidasofia/google-workspace-mcpdocsAVerified
io.github.modelcontextprotocol/filesystemnot in the registry yetfs
io.github.slack/slack-mcpnot in the registry yetchat# Generated by @socketcat/compiler for target: langgraph
# blueprint: com.socketcat/contract-redline v1.0.0 schema: socketcat.dev/blueprint/v0
# This code is yours. Edit it freely. The socketcat_runtime helper is optional and can be vendored.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
import socketcat_runtime as _rt
class State(TypedDict, total=False):
contractRef: object
redline: object
clauses: object
__loop_1: object
draft: object
review: object
def node_AgentInvoke_0(state):
return _rt.run_agent("reader", state, {"contractRef":"contractRef"}, "clauses")
def node_LoopHeader_1(state):
return {}
def node_LoopTick_2(state):
return {"__loop_1": state.get("__loop_1", 0) + 1}
def node_Nop_3(state):
return {}
def node_AgentInvoke_4(state):
return _rt.run_agent("redliner", state, {"review":"review","clauses":"clauses"}, "draft")
def node_AgentInvoke_5(state):
return _rt.run_agent("reviewer", state, {"draft":"draft"}, "review")
def node_AgentInvoke_6(state):
return _rt.run_agent("memoWriter", state, {"draft":"draft"}, "redline")
def node_Ask_7(state):
return _rt.run_ask("Review the redline and risk memo. Approve to share with the counterparty, or send back with notes.", state, "redline")
def route_LoopHeader_1(state):
count = state.get("__loop_1", 0)
return "exit" if (_rt.cond("review.clean == true", state) or count >= 3) else "loop"
def build():
b = StateGraph(State)
b.add_node("AgentInvoke_0", node_AgentInvoke_0)
b.add_node("LoopHeader_1", node_LoopHeader_1)
b.add_node("LoopTick_2", node_LoopTick_2)
b.add_node("Nop_3", node_Nop_3)
b.add_node("AgentInvoke_4", node_AgentInvoke_4)
b.add_node("AgentInvoke_5", node_AgentInvoke_5)
b.add_node("AgentInvoke_6", node_AgentInvoke_6)
b.add_node("Ask_7", node_Ask_7)
b.add_edge(START, "AgentInvoke_0")
b.add_edge("AgentInvoke_0", "AgentInvoke_4")
b.add_conditional_edges("LoopHeader_1", route_LoopHeader_1, {"loop": "AgentInvoke_4", "exit": "Nop_3"})
b.add_edge("LoopTick_2", "LoopHeader_1")
b.add_edge("Nop_3", "AgentInvoke_6")
b.add_edge("AgentInvoke_4", "AgentInvoke_5")
b.add_edge("AgentInvoke_5", "LoopTick_2")
b.add_edge("AgentInvoke_6", "Ask_7")
b.add_edge("Ask_7", END)
return b.compile()
INPUTS = ["contractRef"]
OUTPUTS = ["redline"]
if __name__ == "__main__":
_rt.main(build, INPUTS, OUTPUTS)
▸blueprint.json (the portable format)
{
"id": "com.socketcat/contract-redline",
"flow": {
"type": "sequence",
"blocks": [
{
"in": {
"contractRef": "contractRef"
},
"out": "clauses",
"use": "reader",
"type": "agent"
},
{
"max": 3,
"type": "loop",
"until": "review.clean == true",
"blocks": [
{
"in": {
"review": "review",
"clauses": "clauses"
},
"out": "draft",
"use": "redliner",
"type": "agent"
},
{
"in": {
"draft": "draft"
},
"out": "review",
"use": "reviewer",
"type": "agent"
}
]
},
{
"in": {
"draft": "draft"
},
"out": "redline",
"use": "memoWriter",
"type": "agent"
},
{
"out": "redline",
"type": "ask",
"prompt": "Review the redline and risk memo. Approve to share with the counterparty, or send back with notes."
}
]
},
"tags": [
"legal",
"contracts",
"evaluator-optimizer",
"human-in-the-loop"
],
"title": "Contract Redline",
"agents": {
"reader": {
"model": {
"hint": "fast"
},
"title": "Reader",
"tools": [
"docs.read_doc"
],
"instructions": "Open the contract and extract its clauses: label each by type (liability, term, indemnity, IP, payment, etc.) and capture its exact text. Do not judge yet."
},
"redliner": {
"model": {
"hint": "reasoning"
},
"title": "Redliner",
"tools": [
"fs.read_file"
],
"instructions": "Read the negotiation playbook from disk. Propose the minimal edits that bring off-standard clauses in line with it, quoting the exact replacement text. If you received a review, address every flag and try again. Never soften a position the playbook marks non-negotiable."
},
"reviewer": {
"model": {
"hint": "reasoning"
},
"title": "Reviewer",
"output": {
"type": "object",
"required": [
"clean"
],
"properties": {
"clean": {
"type": "boolean"
},
"notes": {
"type": "string"
}
}
},
"instructions": "Check the redline against the playbook. Flag any clause still off-standard, any edit that overreaches, and any risk a counterparty would reject. Return an object with a 'clean' boolean and specific notes. Sign off only when the redline is defensible and complete."
},
"memoWriter": {
"model": {
"hint": "fast"
},
"title": "Memo Writer",
"tools": [
"chat.post_message"
],
"instructions": "Write a short risk memo for the reviewing lawyer: what was changed, what still carries risk, and what to watch in negotiation. Post a pointer to the legal channel. Do not send anything to the counterparty."
}
},
"estate": {
"draft": {
"type": "object",
"description": "The redliner's current proposed edits."
},
"review": {
"type": "object",
"description": "The reviewer's verdict, including a 'clean' flag."
},
"clauses": {
"type": "array",
"description": "The extracted clauses with their text and type."
}
},
"$schema": "socketcat.dev/blueprint/v0",
"authors": [
{
"url": "https://socketcat.com",
"name": "SocketCat"
}
],
"license": "MIT",
"servers": [
{
"ref": "io.github.adelaidasofia/google-workspace-mcp",
"alias": "docs"
},
{
"ref": "io.github.modelcontextprotocol/filesystem",
"alias": "fs"
},
{
"ref": "io.github.slack/slack-mcp",
"alias": "chat"
}
],
"summary": "Extracts contract clauses, redlines them against your playbook in a review loop, and pauses for a lawyer to approve.",
"targets": [
"langgraph",
"*"
],
"version": "1.0.0",
"interface": {
"inputs": {
"contractRef": {
"type": "string",
"description": "The contract to review, as a drive document id or path."
}
},
"outputs": {
"redline": {
"type": "string",
"description": "The approved redline and risk memo, ready for a human to send."
}
}
},
"extensions": {
"dev.langgraph": {
"checkpointer": "memory"
}
},
"description": "A reader opens the contract from the drive and extracts its clauses. A redliner proposes edits that move off-standard terms toward the company's negotiation playbook (read from disk), and a reviewer checks each edit against that playbook and flags residual risk. The two loop until the reviewer signs off or the round budget is reached. A risk memo is produced and the package pauses for a human lawyer to approve before it is shared. Replace the playbook file with your own standard positions."
}More in Finance & legal
Browse all →Invoice Match
Reads an incoming invoice, matches it against the purchase order and receipt in your database, and branches: clean ones queue for approval, mismatches get a written exception.