Skip to main content Skills Marketplace コミュニティが作成したAIスキルを発見・探索
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill lien-waiver-trackerコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Zipをダウンロード ダウンロード中... name lien-waiver-tracker description Track and manage construction lien waivers. Monitor conditional and unconditional waivers, ensure compliance before payments, and prevent lien exposure. homepage https://datadrivenconstruction.io metadata {"openclaw":{"emoji":"📝","os":["darwin","linux","win32"],"homepage":"https://datadrivenconstruction.io","requires":{"bins":["python3"]}}}
Lien Waiver Tracker
Overview
Track and manage lien waivers throughout the construction payment process. Ensure proper waivers are received before releasing payments, monitor waiver status by subcontractor, and minimize lien exposure.
Lien Waiver Types
┌─────────────────────────────────────────────────────────────────┐
│ LIEN WAIVER TYPES │
├─────────────────────────────────────────────────────────────────┤
│ │
│ CONDITIONAL UNCONDITIONAL │
│ ─────────── ───────────── │
│ 📋 Progress - Conditional ✅ Progress - Unconditional │
│ Effective when paid Immediately effective │
│ Use with payment Use after check clears │
│ │
│ 📋 Final - Conditional ✅ Final - Unconditional │
│ For final payment For final payment │
│ Upon receipt of funds After funds received │
│ │
└─────────────────────────────────────────────────────────────────┘
Technical Implementation
from dataclasses import dataclass, field
from typing import List , Dict , Optional
from datetime import datetime, timedelta
from enum import Enum
class WaiverType (Enum ):
CONDITIONAL_PROGRESS = "conditional_progress"
UNCONDITIONAL_PROGRESS = "unconditional_progress"
CONDITIONAL_FINAL = "conditional_final"
UNCONDITIONAL_FINAL = "unconditional_final"
class WaiverStatus (Enum ):
REQUESTED = "requested"
RECEIVED = "received"
VERIFIED = "verified"
REJECTED = "rejected"
MISSING = "missing"
class PaymentStatus (Enum ):
PENDING = "pending"
APPROVED = "approved"
HELD = "held"
RELEASED = "released"
@dataclass
class Subcontractor :
id : str
name: str
trade: str
contract_amount: float
contact_name: str
contact_email: str
tier: int = 1
@dataclass
:
:
subcontractor_id:
waiver_type: WaiverType
payment_application:
through_date: datetime
amount:
status: WaiverStatus = WaiverStatus.REQUESTED
requested_date: datetime = field(default_factory=datetime.now)
received_date: [datetime] =
verified_by: =
file_path: =
notes: =
:
number:
period_end: datetime
subcontractor_id:
amount_requested:
amount_approved:
retainage:
status: PaymentStatus = PaymentStatus.PENDING
waivers_complete: =
payment_date: [datetime] =
:
subcontractor_id:
subcontractor_name:
total_paid:
unconditional_waivers:
conditional_pending:
exposure:
:
( ):
.project_id = project_id
.project_name = project_name
.subcontractors: [ , Subcontractor] = {}
.waivers: [ , LienWaiver] = {}
.pay_apps: [ , PaymentApplication] = {}
( ) -> Subcontractor:
sub = Subcontractor(
= ,
name=name,
trade=trade,
contract_amount=contract_amount,
contact_name=contact_name,
contact_email=contact_email,
tier=tier
)
.subcontractors[ ] = sub
sub
( ) -> PaymentApplication:
subcontractor_id .subcontractors:
ValueError( )
retainage = amount_requested * retainage_rate
amount_approved = amount_requested - retainage
pay_app = PaymentApplication(
number=number,
period_end=period_end,
subcontractor_id=subcontractor_id,
amount_requested=amount_requested,
amount_approved=amount_approved,
retainage=retainage
)
key =
.pay_apps[key] = pay_app
.request_waiver(subcontractor_id, number, period_end, amount_approved)
pay_app
( ) -> LienWaiver:
waiver_id =
waiver = LienWaiver(
=waiver_id,
subcontractor_id=subcontractor_id,
waiver_type=waiver_type,
payment_application=pay_app_number,
through_date=through_date,
amount=amount
)
.waivers[waiver_id] = waiver
waiver
( ) -> LienWaiver:
waiver_id .waivers:
ValueError( )
waiver = .waivers[waiver_id]
waiver.status = WaiverStatus.RECEIVED
waiver.received_date = datetime.now()
waiver.file_path = file_path
waiver.verified_by = verified_by
._check_pay_app_waivers(waiver.subcontractor_id, waiver.payment_application)
waiver
( ) -> LienWaiver:
waiver_id .waivers:
ValueError( )
waiver = .waivers[waiver_id]
waiver.status = WaiverStatus.VERIFIED
waiver.verified_by = verified_by
waiver
( ) -> LienWaiver:
waiver_id .waivers:
ValueError( )
waiver = .waivers[waiver_id]
waiver.status = WaiverStatus.REJECTED
waiver.notes =
waiver
( ) -> LienWaiver:
waiver_id .waivers:
ValueError( )
waiver = .waivers[waiver_id]
new_type = (WaiverType.UNCONDITIONAL_PROGRESS
waiver.waiver_type == WaiverType.CONDITIONAL_PROGRESS
WaiverType.UNCONDITIONAL_FINAL)
.request_waiver(
waiver.subcontractor_id,
waiver.payment_application,
waiver.through_date,
waiver.amount,
new_type
)
( ):
key =
key .pay_apps:
pay_app = .pay_apps[key]
related_waivers = [
w w .waivers.values()
w.subcontractor_id == subcontractor_id
w.payment_application == pay_app_number
]
pay_app.waivers_complete = (
w.status [WaiverStatus.RECEIVED, WaiverStatus.VERIFIED]
w related_waivers
)
( ) -> LienExposure:
subcontractor_id .subcontractors:
ValueError( )
sub = .subcontractors[subcontractor_id]
total_paid = (
pa.amount_approved pa .pay_apps.values()
pa.subcontractor_id == subcontractor_id
pa.status == PaymentStatus.RELEASED
)
unconditional = (
w.amount w .waivers.values()
w.subcontractor_id == subcontractor_id
w.waiver_type [WaiverType.UNCONDITIONAL_PROGRESS, WaiverType.UNCONDITIONAL_FINAL]
w.status [WaiverStatus.RECEIVED, WaiverStatus.VERIFIED]
)
conditional = (
w.amount w .waivers.values()
w.subcontractor_id == subcontractor_id
w.waiver_type [WaiverType.CONDITIONAL_PROGRESS, WaiverType.CONDITIONAL_FINAL]
w.status [WaiverStatus.RECEIVED, WaiverStatus.VERIFIED]
)
exposure = total_paid - unconditional
LienExposure(
subcontractor_id=subcontractor_id,
subcontractor_name=sub.name,
total_paid=total_paid,
unconditional_waivers=unconditional,
conditional_pending=conditional,
exposure=exposure
)
( ) -> [ ]:
missing = []
waiver .waivers.values():
waiver.status [WaiverStatus.REQUESTED, WaiverStatus.MISSING]:
sub = .subcontractors.get(waiver.subcontractor_id)
missing.append({
: waiver. ,
: sub.name sub waiver.subcontractor_id,
: waiver.payment_application,
: waiver.amount,
: waiver.waiver_type.value,
: waiver.requested_date,
: (datetime.now() - waiver.requested_date).days
})
(missing, key= x: -x[ ])
( ) -> :
subcontractor_id .subcontractors:
ValueError( )
sub = .subcontractors[subcontractor_id]
waivers = [w w .waivers.values() w.subcontractor_id == subcontractor_id]
by_status = {}
w waivers:
s = w.status.value
by_status[s] = by_status.get(s, ) +
{
: sub.name,
: (waivers),
: by_status,
: (w.amount w waivers),
: (w.amount w waivers w.status == WaiverStatus.VERIFIED)
}
( ) -> :
key =
key .pay_apps:
{ : , : }
pay_app = .pay_apps[key]
waivers = [
w w .waivers.values()
w.subcontractor_id == subcontractor_id
w.payment_application == pay_app_number
w.waiver_type == WaiverType.CONDITIONAL_PROGRESS
]
waivers:
{ : , : }
w waivers:
w.status [WaiverStatus.RECEIVED, WaiverStatus.VERIFIED]:
{ : , : }
{ : , : , : pay_app.amount_approved}
( ) -> :
lines = [
,
,
,
,
,
,
,
,
,
,
,
,
,
,
]
total_exposure =
sub_id .subcontractors:
exposure = .calculate_exposure(sub_id)
total_exposure += exposure.exposure
lines.append(
)
lines.extend([
,
,
,
])
missing = .get_missing_waivers()
missing:
lines.append( )
lines.append( )
m missing[: ]:
lines.append(
)
:
lines.append( )
.join(lines)
Quick Start
tracker = LienWaiverTracker("PRJ-001" , "Office Tower" )
tracker.add_subcontractor(
"SUB-001" , "ABC Mechanical" , "HVAC" ,
contract_amount=500000 ,
contact_name="John Smith" ,
contact_email="john@abcmech.com"
)
tracker.add_subcontractor(
"SUB-002" , "XYZ Electric" , "Electrical" ,
contract_amount=350000 ,
contact_name="Jane Doe" ,
contact_email="jane@xyzelectric.com"
)
pa1 = tracker.create_payment_application(
number=1 ,
period_end=datetime.now(),
subcontractor_id="SUB-001" ,
amount_requested=50000
)
waiver_id = f"LW-SUB-001-1"
tracker.receive_waiver(waiver_id, "/waivers/sub001_pa1.pdf" , "PM" )
result = tracker.can_release_payment("SUB-001" , 1 )
print (f"Can release: {result['can_release' ]} - {result['reason' ]} " )
exposure = tracker.calculate_exposure("SUB-001" )
print (f"Lien exposure: ${exposure.exposure:,.2 f} " )
print (tracker.generate_report())
Requirements
pip install (no external dependencies)
class
LienWaiver
id
str
str
int
float
Optional
None
str
""
str
""
str
""
@dataclass
class
PaymentApplication
int
str
float
float
float
bool
False
Optional
None
@dataclass
class
LienExposure
str
str
float
float
float
float
class
LienWaiverTracker
"""Track and manage construction lien waivers."""
def
__init__
self, project_id: str , project_name: str
self
self
self
Dict
str
self
Dict
str
self
Dict
str
def
add_subcontractor
self, id : str , name: str , trade: str ,
contract_amount: float , contact_name: str ,
contact_email: str , tier: int = 1
"""Add subcontractor to tracking."""
id
id
self
id
return
def
create_payment_application
self, number: int , period_end: datetime,
subcontractor_id: str , amount_requested: float ,
retainage_rate: float = 0.10
"""Create payment application record."""
if
not
in
self
raise
f"Subcontractor {subcontractor_id} not found"
f"{subcontractor_id} -{number} "
self
self
return
def
request_waiver
self, subcontractor_id: str , pay_app_number: int ,
through_date: datetime, amount: float ,
waiver_type: WaiverType = WaiverType.CONDITIONAL_PROGRESS
"""Request lien waiver from subcontractor."""
f"LW-{subcontractor_id} -{pay_app_number} "
id
self
return
def
receive_waiver
self, waiver_id: str , file_path: str ,
verified_by: str = ""
"""Record receipt of lien waiver."""
if
not
in
self
raise
f"Waiver {waiver_id} not found"
self
self
return
def
verify_waiver
self, waiver_id: str , verified_by: str
"""Verify waiver details are correct."""
if
not
in
self
raise
f"Waiver {waiver_id} not found"
self
return
def
reject_waiver
self, waiver_id: str , reason: str
"""Reject waiver (incorrect amount, wrong form, etc.)."""
if
not
in
self
raise
f"Waiver {waiver_id} not found"
self
f"Rejected: {reason} "
return
def
convert_to_unconditional
self, waiver_id: str , payment_date: datetime
"""Convert conditional waiver to unconditional after payment clears."""
if
not
in
self
raise
f"Waiver {waiver_id} not found"
self
if
else
return
self
def
_check_pay_app_waivers
self, subcontractor_id: str , pay_app_number: int
"""Check if all waivers for pay app are received."""
f"{subcontractor_id} -{pay_app_number} "
if
not
in
self
return
self
for
in
self
if
and
all
in
for
in
def
calculate_exposure
self, subcontractor_id: str
"""Calculate lien exposure for subcontractor."""
if
not
in
self
raise
f"Subcontractor {subcontractor_id} not found"
self
sum
for
in
self
if
and
sum
for
in
self
if
and
in
and
in
sum
for
in
self
if
and
in
and
in
return
def
get_missing_waivers
self
List
Dict
"""Get list of missing or pending waivers."""
for
in
self
if
in
self
"waiver_id"
id
"subcontractor"
if
else
"pay_app"
"amount"
"type"
"requested_date"
"days_outstanding"
return
sorted
lambda
"days_outstanding"
def
get_waiver_status_by_sub
self, subcontractor_id: str
Dict
"""Get waiver status summary for subcontractor."""
if
not
in
self
raise
f"Subcontractor {subcontractor_id} not found"
self
for
in
self
if
for
in
0
1
return
"subcontractor"
"total_waivers"
len
"by_status"
"total_amount"
sum
for
in
"verified_amount"
sum
for
in
if
def
can_release_payment
self, subcontractor_id: str , pay_app_number: int
Dict
"""Check if payment can be released."""
f"{subcontractor_id} -{pay_app_number} "
if
not
in
self
return
"can_release"
False
"reason"
"Payment application not found"
self
for
in
self
if
and
and
if
not
return
"can_release"
False
"reason"
"No conditional waiver received"
for
in
if
not
in
return
"can_release"
False
"reason"
f"Waiver {w.id } not verified"
return
"can_release"
True
"reason"
"All waivers verified"
"amount"
def
generate_report
self
str
"""Generate lien waiver status report."""
"# Lien Waiver Status Report"
""
f"**Project:** {self.project_name} "
f"**Date:** {datetime.now().strftime('%Y-%m-%d' )} "
""
"## Summary"
""
f"- Total Subcontractors: {len (self.subcontractors)} "
f"- Total Waivers Tracked: {len (self.waivers)} "
f"- Missing Waivers: {len (self.get_missing_waivers())} "
""
"## Exposure by Subcontractor"
""
"| Subcontractor | Paid | Unconditional | Exposure |"
"|---------------|------|---------------|----------|"
0
for
in
self
self
f"| {exposure.subcontractor_name} | ${exposure.total_paid:,.0 f} | "
f"${exposure.unconditional_waivers:,.0 f} | ${exposure.exposure:,.0 f} |"
f"| **TOTAL** | | | **${total_exposure:,.0 f} ** |"
""
"## Missing Waivers"
""
self
if
"| Subcontractor | Pay App | Amount | Days Outstanding |"
"|---------------|---------|--------|------------------|"
for
in
10
f"| {m['subcontractor' ]} | #{m['pay_app' ]} | "
f"${m['amount' ]:,.0 f} | {m['days_outstanding' ]} |"
else
"*No missing waivers*"
return
"\n"
datadrivenconstruction
datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction
GitHub リポジトリを開く