Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill cash-flow-forecastergit clone --depth 1 https://github.com/datadrivenconstruction/DDC_Skills_for_AI_Agents_in_ConstructionWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/cash-flow-forecaster)<a href="https://agentmods.dev/skills/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/cash-flow-forecaster"><img src="https://agentmods.dev/badge/skills/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/cash-flow-forecaster/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/cash-flow-forecaster"><img src="https://agentmods.dev/badge/skills/datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/cash-flow-forecaster.svg" alt="Reviewed on agentmods" width="80" height="20"></a>- NVIDIA SkillSpector pass
What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00025 | $0.03408 |
| Opus 5 | $0.00013 | $0.01704 |
| Sonnet 5 | $0.00005 | $0.00682 |
| Haiku 4.5 | $0.00003 | $0.00341 |
Grade A, and why
cash-flow-forecaster scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 12d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
Copies of this mod
1 near-identical copy found in the catalogue:
- cash-flow-forecaster — 100% identical, 0 lines differ
How it starts
The opening of the file, as written. The whole thing — 446 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Cash Flow Forecaster
Business Case
Problem Statement
Poor cash flow management causes issues:
- Insufficient funds for payments
- Missed early payment discounts
- Inaccurate financial projections
- Difficulty in financing negotiations
Solution
Generate cash flow forecasts from schedule and cost data, including S-curve projections and payment timing analysis.
Business Value
- Financial planning - Accurate funding requirements
- Vendor relations - Timely payments
- Financing - Support loan draw schedules
- Decision support - Cash position awareness
Technical Implementation
import pandas as pd
import numpy as np
from datetime import datetime, date, timedelta
from typing import Dict, Any, List, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum
class CashFlowType(Enum):
"""Cash flow types."""
INFLOW = "inflow"
OUTFLOW = "outflow"
class PaymentTerms(Enum):
"""Standard payment terms."""
NET_30 = 30
NET_45 = 45
NET_60 = 60
NET_90 = 90
MILESTONE = 0
PROGRESS = 0
@dataclass
class CostItem:
"""Cost item for cash flow."""
item_id: str
description: str
total_amount: float
start_date: date
end_date: date
payment_terms: PaymentTerms
distribution: str = "linear" # linear, front_loaded, back_loaded, s_curve
retention_percent: float = 0.10
category: str = ""
@dataclass
class PaymentSchedule:
"""Scheduled payment."""
payment_id: str
item_id: str
description: str
amount: float
due_date: date
payment_type: CashFlowType
is_retention: bool = False
paid: bool = False
paid_date: Optional[date] = None
@dataclass
class CashFlowPeriod:
"""Cash flow for a period."""
period_start: date
period_end: date
inflows: float
outflows: float
net_cash_flow: float
cumulative_cash_flow: float
opening_balance: float
closing_balance: float
class CashFlowForecaster:
"""Forecast project cash flow."""
def __init__(self, project_name: str, project_start: date, project_end: date,
initial_balance: float = 0, currency: str = "USD"):
self.project_name = project_name
self.project_start = project_start
self.project_end = project_end
self.initial_balance = initial_balance
self.currency = currency
self.cost_items: List[CostItem] = []
self.revenue_items: List[CostItem] = []
self.payments: List[PaymentSchedule] = []
self._payment_counter = 0
def add_cost_item(self, item_id: str, description: str, total_amount: float,
start_date: date, end_date: date,
payment_terms: PaymentTerms = PaymentTerms.NET_30,
distribution: str = "linear",
retention: float = 0.10,
category: str = "") -> CostItem:
"""Add cost item (outflow)."""
item = CostItem(
item_id=item_id,
description=description,
total_amount=total_amount,
start_date=start_date,
end_date=end_date,
payment_terms=payment_terms,
distribution=distribution,
retention_percent=retention,
category=category
)
self.cost_items.append(item)
return item
def add_revenue_item(self, item_id: str, description: str, total_amount: float,
start_date: date, end_date: date,
payment_terms: PaymentTerms = PaymentTerms.NET_30,
distribution: str = "linear",
retention: float = 0.10) -> CostItem:
"""Add revenue item (inflow)."""
item = CostItem(
item_id=item_id,
description=description,
total_amount=total_amount,
start_date=start_date,
end_date=end_date,
payment_terms=payment_terms,
distribution=distribution,
retention_percent=retention
)
self.revenue_items.append(item)
return item
def _distribute_amount(self, total: float, start: date, end: date,
distribution: str, periods: int) -> List[float]:
"""Distribute amount over periods based on distribution type."""
if periods <= 0:
return [total]
if distribution == "linear":
return [total / periods] * periods
elif distribution == "front_loaded":
# More at the beginning
weights = [periods - i for i in range(periods)]
total_weight = sum(weights)
return [total * w / total_weight for w in weights]
elif distribution == "back_loaded":
# More at the end
weights = [i + 1 for i in range(periods)]
total_weight = sum(weights)
return [total * w / total_weight for w in weights]
elif distribution == "s_curve":
# S-curve distribution
x = np.linspace(-3, 3, periods)
weights = 1 / (1 + np.exp(-x))
weights = weights / weights.sum()
return [total * w for w in weights]
else:
return [total / periods] * periods
def generate_payment_schedule(self, period_type: str = "monthly") -> List[PaymentSchedule]:
"""Generate payment schedule from cost items."""
self.payments = []
# Process cost items (outflows)
for item in self.cost_items:
self._generate_item_payments(item, CashFlowType.OUTFLOW, period_type)
# Process revenue items (inflows)
for item in self.revenue_items:
self._generate_item_payments(item, CashFlowType.INFLOW, period_type)
return sorted(self.payments, key=lambda x: x.due_date)
def _generate_item_payments(self, item: CostItem, flow_type: CashFlowType,
period_type: str):
"""Generate payments for a single item."""
# Calculate number of periods
if period_type == "monthly":
months = (item.end_date.year - item.start_date.year) * 12 + \
(item.end_date.month - item.start_date.month) + 1
periods = max(1, months)
else: # weekly
days = (item.end_date - item.start_date).days
periods = max(1, days // 7)
# Distribute amount
net_amount = item.total_amount * (1 - item.retention_percent)
amounts = self._distribute_amount(net_amount, item.start_date, item.end_date,
item.distribution, periods)
# Create payments
current_date = item.start_date
for i, amount in enumerate(amounts):
# Calculate payment due date based on terms
if item.payment_terms == PaymentTerms.MILESTONE:
due_date = current_date
else:
due_date = current_date + timedelta(days=item.payment_terms.value)
self._payment_counter += 1
payment = PaymentSchedule(
payment_id=f"PAY-{self._payment_counter:05d}",
item_id=item.item_id,
description=f"{item.description} - Period {i+1}",
amount=amount,
due_date=due_date,
payment_type=flow_type
)
self.payments.append(payment)
# Move to next period
if period_type == "monthly":
if current_date.month == 12:
current_date = date(current_date.year + 1, 1, current_date.day)
else:
try:
current_date = date(current_date.year, current_date.month + 1, current_date.day)
except ValueError:
# Handle months with fewer days
current_date = date(current_date.year, current_date.month + 1, 28)
else:
current_date += timedelta(days=7)
# Add retention release at project end
if item.retention_percent > 0:
retention_amount = item.total_amount * item.retention_percent
self._payment_counter += 1
retention_payment = PaymentSchedule(
payment_id=f"PAY-{self._payment_counter:05d}",
item_id=item.item_id,
description=f"{item.description} - Retention Release",
amount=retention_amount,
due_date=self.project_end + timedelta(days=60),
payment_type=flow_type,
is_retention=True
)
self.payments.append(retention_payment)
def generate_cash_flow_forecast(self, period_type: str = "monthly") -> List[CashFlowPeriod]:
"""Generate cash flow forecast."""
if not self.payments:
self.generate_payment_schedule(period_type)
# Group payments by period
periods = []
current_date = self.project_start
cumulative = 0
balance = self.initial_balance
while current_date <= self.project_end + timedelta(days=90):
# Calculate period end
if period_type == "monthly":
if current_date.month == 12:
period_end = date(current_date.year + 1, 1, 1) - timedelta(days=1)
else:
period_end = date(current_date.year, current_date.month + 1, 1) - timedelta(days=1)
else:
period_end = current_date + timedelta(days=6)
# Filter payments for this period
period_payments = [p for p in self.payments
if current_date <= p.due_date <= period_end]
inflows = sum(p.amount for p in period_payments
if p.payment_type == CashFlowType.INFLOW)
outflows = sum(p.amount for p in period_payments
if p.payment_type == CashFlowType.OUTFLOW)
net = inflows - outflows
cumulative += net
period = CashFlowPeriod(
period_start=current_date,
period_end=period_end,
inflows=inflows,
outflows=outflows,
net_cash_flow=net,
cumulative_cash_flow=cumulative,
opening_balance=balance,
closing_balance=balance + net
)
periods.append(period)
balance = period.closing_balance
# Move to next period
current_date = period_end + timedelta(days=1)
return periods
def generate_s_curve(self) -> pd.DataFrame:
"""Generate S-curve data (cumulative costs over time)."""
forecast = self.generate_cash_flow_forecast()
# Costs only (outflows)
data = []
cumulative_cost = 0
total_cost = sum(item.total_amount for item in self.cost_items)
for period in forecast:
cumulative_cost += period.outflows
percent_complete = (cumulative_cost / total_cost * 100) if total_cost > 0 else 0
data.append({
'date': period.period_end,
'period_cost': period.outflows,
'cumulative_cost': cumulative_cost,
'percent_complete': round(percent_complete, 1),
'total_budget': total_cost
})
return pd.DataFrame(data)
def get_funding_requirements(self, buffer_percent: float = 0.10) -> Dict[str, Any]:
"""Calculate funding requirements."""
forecast = self.generate_cash_flow_forecast()
# Find peak negative cash flow
min_balance = min(p.closing_balance for p in forecast)
peak_funding = abs(min(0, min_balance))
# Add buffer
required_funding = peak_funding * (1 + buffer_percent)
# Monthly funding needs
monthly_needs = []
for period in forecast:
if period.net_cash_flow < 0:
monthly_needs.append({
'month': period.period_start.strftime('%Y-%m'),
'funding_needed': abs(period.net_cash_flow)
})
return {
'peak_funding_required': round(required_funding, 2),
'peak_funding_month': min(forecast, key=lambda x: x.closing_balance).period_start.strftime('%Y-%m'),
'total_outflows': sum(p.outflows for p in forecast),
'total_inflows': sum(p.inflows for p in forecast),
'monthly_funding_needs': monthly_needs,
'buffer_percent': buffer_percent
}
def export_forecast(self, output_path: str):
"""Export cash flow forecast to Excel."""
forecast = self.generate_cash_flow_forecast()
s_curve = self.generate_s_curve()
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
# Cash flow forecast
forecast_df = pd.DataFrame([{
'Period Start': p.period_start,
'Period End': p.period_end,
'Inflows': p.inflows,
'Outflows': p.outflows,
'Net Cash Flow': p.net_cash_flow,
'Cumulative': p.cumulative_cash_flow,
'Opening Balance': p.opening_balance,
'Closing Balance': p.closing_balance
} for p in forecast])
forecast_df.to_excel(writer, sheet_name='Cash Flow', index=False)
# S-curve
s_curve.to_excel(writer, sheet_name='S-Curve', index=False)
# Payment schedule
payments_df = pd.DataFrame([{
'ID': p.payment_id,
'Item': p.item_id,
'Description': p.description,
'Amount': p.amount,
'Due Date': p.due_date,
'Type': p.payment_type.value,
'Retention': p.is_retention
} for p in self.payments])
payments_df.to_excel(writer, sheet_name='Payments', index=False)
return output_path
What ships with it
2 files beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 12d ago First seen · 446 lines · 25 tokens per session scan A 5540e3d0606b
cash-flow-forecaster is a skill published in the GitHub repository datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction (310 stars, last pushed 21d ago), licensed MIT. It adds 25 tokens to every session and 3,408 once invoked, about $0.0001 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other skills, from other repositories
close-management
Manage the month-end close process with task sequencing, dependencies, and status tracking. Use when planning the close calendar, tracking close progress, identifying blockers, or sequencing close activities by day.
catchup
Summarize and review what changed while you were away. Use after a weekend, vacation, or flight to check missed PRs, git commits, Linear tickets, and meetings — one prioritized brief, not a firehose.
phx-deps-update
Bump outdated Hex deps — inventory, snapshot changelogs, update, fix breaks, split reviewable PRs (patches bundled, majors solo). Use to upgrade/bump Elixir dependencies or when versions fall behind. NOT for deps.get failures (phx-investigate).
stripe-payments
Add Stripe payments to a web app — Checkout Sessions, Payment Intents, subscriptions, webhooks, customer portal, and pricing pages. Covers the decision of which Stripe API to use, produces working integration code, and handles webhook verification. No MCP server needed — uses Stripe npm package directly. Triggers…
proposal-writer
Write a client proposal, quote, scope of work, or engagement letter for a service business. Covers project understanding, scope, timeline, pricing presentation, and terms. Use whenever the user asks for a proposal, quote, project proposal, client proposal, SOW, statement of work, engagement letter, or B2B service…
whats-next
Suggests the 3 most impactful next actions based on full developer context — git, Linear, PRs, and current conversation. Prioritizes blockers, unblocked items, and momentum. Use when deciding what to work on next or after finishing a task.