Skip to content

Agent Workflow Cookbook

This cookbook walks through the full “plain English to production model” workflow. Each step shows the prompt you can send to your MCP-compatible AI agent, the Bridge Town tool call it should make, a representative response, and the model code or output shape to expect.

  • A Bridge Town account at app.bridgetown.builders
  • Claude, Codex, Gemini, or another MCP-compatible client connected to Bridge Town (see Quick Start)
  • Editor or Owner role on the workspace

Prompt to your agent:

Create a new project called revenue-forecast for a 12-month revenue model.

MCP tool call:

{
"name": "create_project",
"arguments": {
"project_name": "revenue-forecast",
"description": "12-month revenue forecast with three product lines"
}
}

Representative response:

{
"project": "revenue-forecast",
"description": "12-month revenue forecast with three product lines",
"org": "acme",
"clone_url": "https://git.bridgetown.builders/acme/revenue-forecast.git",
"gitea_id": 128,
"run_py": "\"\"\"Bridge Town model entry point.\"\"\"\n...",
"model_py": "\"\"\"Starter financial model.\"\"\"\n..."
}

run_py and model_py contain the default scaffold when scaffold is omitted or true. If you pass "scaffold": false, both fields are null.


Prompt to your agent:

In the revenue-forecast project, create a model called forecast that projects 12 months of revenue for three product lines: SaaS starting at $50k per month with 8% monthly growth, Services starting at $30k per month with 3% monthly growth, and Marketplace starting at $15k per month with 12% monthly growth. Write chart-ready output and a summary.

MCP tool call:

Use the Python code below as the content string.

{
"name": "create_file",
"arguments": {
"project_name": "revenue-forecast",
"path": "model/forecast.py",
"content": "<paste the Python code shown below>",
"commit_message": "feat: add 12-month revenue forecast model"
}
}

Model code (model/forecast.py):

"""12-month revenue forecast with chart-ready outputs."""
import json
from pathlib import Path
MONTHS = 12
LINES = {
"SaaS": {"base": 50_000, "growth": 0.08},
"Services": {"base": 30_000, "growth": 0.03},
"Marketplace": {"base": 15_000, "growth": 0.12},
}
results = {}
for name, params in LINES.items():
monthly = []
revenue = params["base"]
for _month in range(MONTHS):
monthly.append(round(revenue, 2))
revenue *= 1 + params["growth"]
results[name] = monthly
chart_data = {
"x": [f"2026-{month:02d}" for month in range(1, MONTHS + 1)],
"series": [
{"name": name, "values": values}
for name, values in results.items()
],
}
summary = {
"line_totals": {
name: round(sum(values), 2)
for name, values in results.items()
},
"total_revenue": round(sum(sum(values) for values in results.values()), 2),
}
Path("/outputs/chart_data.json").write_text(json.dumps(chart_data, indent=2))
Path("/outputs/summary.json").write_text(json.dumps(summary, indent=2))
print("12-Month Revenue Forecast")
print("=" * 40)
for name, values in results.items():
total = sum(values)
print(f"{name:12}: ${total:>12,.2f}")
print("=" * 40)
print(f"{'Total':12}: ${summary['total_revenue']:>12,.2f}")

Representative response:

{
"path": "model/forecast.py",
"project": "revenue-forecast",
"commit_sha": "abc1234def5678901234567890abcdef12345678"
}

Prompt to your agent:

Run the revenue-forecast project.

MCP tool call:

{
"name": "run",
"arguments": {
"scope": "project",
"mode": "sync",
"project_name": "revenue-forecast"
}
}

Representative response:

{
"run_id": "2f9e8a5b-31d4-4a2d-9ef0-8b8e7f3a2c91",
"project": "revenue-forecast",
"branch": "main",
"commit_sha": "abc1234def5678901234567890abcdef12345678",
"status": "success",
"exit_code": 0,
"stdout": "12-Month Revenue Forecast\n========================================\nSaaS : $ 948,856.32\nServices : $ 425,760.89\nMarketplace : $ 361,997.00\n========================================\nTotal : $1,736,614.21\n",
"stderr": "",
"stdout_truncated": false,
"stderr_truncated": false,
"outputs": {
"chart_data.json": {
"x": ["2026-01", "2026-02", "2026-03"],
"series": [
{"name": "SaaS", "values": [50000.0, 54000.0, 58320.0]},
{"name": "Services", "values": [30000.0, 30900.0, 31827.0]},
{"name": "Marketplace", "values": [15000.0, 16800.0, 18816.0]}
]
},
"summary.json": {
"line_totals": {
"SaaS": 948856.32,
"Services": 425760.89,
"Marketplace": 361997.0
},
"total_revenue": 1736614.21
}
},
"duration_seconds": 1.23,
"data_snapshot_ref": null,
"error": null
}

The run response contains three values you usually need:

  1. stdout for a quick human-readable summary
  2. outputs for files written to /outputs/
  3. run_id, a UUID you can pass to get_run_output, get_run, or dashboard tools

To fetch one output from a completed run, prefer get_run_output. It avoids pulling the full run envelope and supports individual outputs up to 10 MiB:

{
"name": "get_run_output",
"arguments": {
"run_id": "2f9e8a5b-31d4-4a2d-9ef0-8b8e7f3a2c91",
"output_name": "summary.json",
"encoding": "auto"
}
}

To retrieve a past run:

{
"name": "get_run",
"arguments": {
"run_id": "2f9e8a5b-31d4-4a2d-9ef0-8b8e7f3a2c91"
}
}

After reviewing the base case, test a higher SaaS growth scenario.

Prompt to your agent:

Bump the SaaS growth rate from 8% to 12% per month in the forecast model.

MCP tool call:

{
"name": "patch_file",
"arguments": {
"project_name": "revenue-forecast",
"path": "model/forecast.py",
"find_text": " \"SaaS\": {\"base\": 50_000, \"growth\": 0.08},",
"replace_text": " \"SaaS\": {\"base\": 50_000, \"growth\": 0.12},",
"expected_occurrences": 1,
"commit_message": "feat: raise SaaS growth assumption to 12%"
}
}

Representative response:

{
"path": "model/forecast.py",
"project": "revenue-forecast",
"commit_sha": "bcd2345ef678901234567890abcdef123456789a",
"replacements_applied": 1
}

Prompt to your agent:

Rerun the project and show me the new totals.

MCP tool call:

{
"name": "run",
"arguments": {
"scope": "project",
"mode": "sync",
"project_name": "revenue-forecast"
}
}

Representative stdout from the patched model:

12-Month Revenue Forecast
========================================
SaaS : $1,206,656.66
Services : $ 425,760.89
Marketplace : $ 361,997.00
========================================
Total : $1,994,414.55

The SaaS line increased from $948,856.32 to $1,206,656.66, a $257,800.34 scenario delta.


Turn the chart output into a line chart. The important detail is that output_key must select an object that directly matches the chart schema. Because the model wrote /outputs/chart_data.json with top-level x and series keys, use "output_key": "chart_data.json".

Prompt to your agent:

Create a dashboard called revenue-chart from run 2f9e8a5b-31d4-4a2d-9ef0-8b8e7f3a2c91, using the chart_data.json output.

MCP tool call:

{
"name": "create_dashboard",
"arguments": {
"project_name": "revenue-forecast",
"dashboard_name": "revenue-chart",
"chart_type": "line",
"model_run_id": "2f9e8a5b-31d4-4a2d-9ef0-8b8e7f3a2c91",
"output_key": "chart_data.json",
"description": "12-month revenue forecast by product line",
"subtitle": "Base case - April 2026 assumptions"
}
}

Representative response:

{
"dashboard_id": "7c0e7229-b05e-4548-a067-76e2afda77b9",
"dashboard_name": "revenue-chart",
"project": "revenue-forecast",
"chart_type": "line",
"model_run_id": "2f9e8a5b-31d4-4a2d-9ef0-8b8e7f3a2c91",
"has_html": true,
"created": true,
"created_at": "2026-04-28T10:00:00+00:00",
"updated_at": "2026-04-28T10:00:00+00:00"
}

Generate a time-limited, anonymous share URL. This requires a Pro plan.

Prompt to your agent:

Share the revenue-chart dashboard for 72 hours.

MCP tool call:

{
"name": "share_dashboard",
"arguments": {
"project_name": "revenue-forecast",
"dashboard_name": "revenue-chart",
"expires_hours": 72
}
}

Representative response:

{
"dashboard_name": "revenue-chart",
"project": "revenue-forecast",
"share_url": "https://s3.bridgetown.builders/dashboards/revenue-chart.html?X-Amz-Expires=259200",
"expires_hours": 72,
"embed_snippet": "<iframe\n src=\"https://s3.bridgetown.builders/dashboards/revenue-chart.html?X-Amz-Expires=259200\"\n title=\"revenue-chart\"\n width=\"100%\"\n height=\"600px\"\n frameborder=\"0\"\n allowfullscreen\n></iframe>"
}

Paste the share_url into Slack, email, or a Notion doc. Paste the embed_snippet into an internal wiki or CMS.


Variation: Import data from Google Sheets first

Section titled “Variation: Import data from Google Sheets first”

If your assumptions live in a Google Sheet rather than hard-coded constants, follow this pre-modeling flow:

  1. Connect the sheet through OAuth in the web app.
  2. Import the assumptions tab.
{
"name": "connect_google_sheet",
"arguments": {
"sheet_url": "https://docs.google.com/spreadsheets/d/ABC123/edit",
"project_name": "revenue-forecast",
"tab_names": ["Assumptions"]
}
}
  1. Query the snapshot to verify the import.
{
"name": "query_data",
"arguments": {
"project_name": "revenue-forecast",
"sql": "SELECT * FROM revenue_forecast_Assumptions"
}
}
  1. Update the model to read from /data/ at runtime instead of using hard-coded constants.
  2. Export results back after the run with write_gsheet (spec.mode="replace" or spec.mode="append").

See the full Google Sheets Integration guide for step-by-step screenshots, formatting presets, and scheduled refresh.


For production workflows, avoid patching main directly. Use branches and pull requests.

{
"name": "create_branch",
"arguments": {
"project_name": "revenue-forecast",
"branch_name": "scenario/aggressive-saas",
"base_branch": "main"
}
}

Repeat Step 5 but add "branch": "scenario/aggressive-saas" to the patch_file call.

Repeat Step 6 but add "branch": "scenario/aggressive-saas" to the run call.

{
"name": "create_pull_request",
"arguments": {
"project_name": "revenue-forecast",
"title": "Raise SaaS growth to 12%",
"head_branch": "scenario/aggressive-saas",
"body": "Increases SaaS monthly growth from 8% to 12% based on updated pipeline assumptions."
}
}

A teammate approves with review_pull_request, then an Owner merges with merge_pull_request.

See the Team Collaboration guide for full details on roles, notifications, and templates.


StepToolKey arguments
1create_projectproject_name, description
2create_fileproject_name, path, content
3runscope: project, mode: sync, project_name
4get_run_outputrun_id, output_name
5patch_fileproject_name, path, find_text, replace_text
6runSame as Step 3
7create_dashboardproject_name, dashboard_name, chart_type, model_run_id, output_key
8share_dashboardproject_name, dashboard_name, expires_hours