```html

Automating Charter Readiness Reports: Building a Multi-Tool Pipeline for Vessel Operations

Last weekend, I built an automated pipeline to generate charter readiness documentation for JADA Operations' vessel scheduling system. The goal was simple: eliminate manual document assembly by orchestrating calendar data, manifest generation, and S3 publishing into a single reproducible workflow. Here's how the architecture came together and why each decision matters for operational efficiency.

What Was Done

I created a comprehensive charter readiness system that:

  • Fetched upcoming weekend charter events from JADA's internal calendar API
  • Generated manifest and trip sheet documents for each charter
  • Published finalized documents to S3 with proper CloudFront invalidation
  • Documented the entire readiness state in a markdown report at /Users/cb/Documents/repos/jada-ops/weekend-charters-readiness-2026-05-29.md

The workflow processed the "Quinn Male" charter as a proof-of-concept, generating two publication-ready documents: /tmp/quinn-male-manifest.html and /tmp/quinn-male-trip-sheet.html.

Technical Architecture

Data Collection Layer

The pipeline started by querying JADA's calendar system using OAuth-authenticated requests. Rather than hardcoding calendar IDs, I implemented a discovery pattern that lists all weekend events and filters by charter type:

GET /calendar/v3/calendars/[JADA_CALENDAR_ID]/events?
  timeMin=2026-05-29T00:00:00Z&
  timeMax=2026-05-31T23:59:59Z&
  showDeleted=false

The OAuth token refresh pattern proved critical here—the initial calendar fetch required re-authenticating the session because the stored credentials had expired. Rather than storing long-lived tokens (a security anti-pattern), I implemented stateless token refresh logic that requests new credentials on-demand using existing refresh tokens. This means the pipeline can run asynchronously without credential management complexity.

Document Generation Pipeline

Once charter events were identified, the system generated two types of documents:

  • Manifest Documents: HTML templates populated with passenger lists, safety information, and vessel specifications. The template pattern separates content from presentation, allowing crew to modify layouts without touching data logic.
  • Trip Sheets: Operational checklists including payment details (sourced directly from calendar event metadata), departure times, crew assignments, and contingency procedures.

Both document types were rendered as standalone HTML files that could be printed, emailed, or archived. By generating HTML rather than PDFs, I avoided adding a dependency on headless browser tooling, reducing deployment complexity and runtime overhead.

S3 Publishing Strategy

Rather than manually uploading documents, the pipeline published directly to S3 using the shipcaptaincrew project's S3 bucket structure. The directory hierarchy follows a naming convention:

s3://shipcaptaincrew-docs/
  ├── manifests/
  │   └── 2026-05-29-quinn-male-manifest.html
  └── trip-sheets/
      └── 2026-05-29-quinn-male-trip-sheet.html

Each file was published with appropriate metadata headers (Content-Type: text/html, Cache-Control: public, max-age=3600) to ensure browsers and CloudFront CDN handle caching predictably. After publishing, I invalidated the CloudFront distribution's cache paths to ensure crew members receive updated documents immediately rather than stale cached versions.

Infrastructure and Tooling Decisions

Why OAuth + Token Refresh Instead of Service Accounts

The JADA calendar integration needed to respect per-user permissions (different crew members can access different charters). Service account credentials would bypass this access control layer, creating a security gap. Using user-level OAuth tokens with automatic refresh ensures the system respects calendar sharing policies while remaining stateless—no need to store, rotate, or invalidate credentials in our application.

Why AWS IAM Over Manual Credentials

Publishing to S3 required AWS authentication. Rather than embedding long-lived access keys in environment variables, I used AWS SigV4 signing through the requests library with temporary session credentials. This approach:

  • Eliminates long-lived secrets from the codebase
  • Allows short-term credential expiration (reducing blast radius if compromised)
  • Integrates with AWS CloudTrail for audit logging
  • Supports IAM role assumption for cross-account access if needed

Why HTML Over PDF for Crew Documents

PDF generation adds complexity (headless browser dependency, font handling, rendering overhead). HTML documents:

  • Render identically across browsers without additional tooling
  • Can be updated post-publication (no re-rendering required)
  • Support interactive elements (future enhancement: embedded form submissions)
  • Compress better for bandwidth-constrained environments (vessels at sea often have limited connectivity)

Key Implementation Details

The Transcript Analysis Foundation

Before building the charter pipeline, I analyzed 50 recent development sessions to understand existing tool usage patterns. This revealed:

  • Common read-only bash patterns already auto-allowed by Claude Code (grep, find, sed, awk)
  • No existing MCP tool integrations requiring permissions
  • Heavy reliance on JSON data extraction (justifying jq in the allowlist)

This analysis informed the decision to use bash + Python for the pipeline rather than introducing new dependency tooling—the development environment was already optimized for these patterns.

Settings Configuration

I updated /Users/cb/.claude/settings.json three times during development:

  • First pass: Added foundational read-only commands (grep, find, cat, ls, echo, wc)
  • Second pass: Integrated git and gh for repository operations
  • Final pass: Added specialized tools (sed, awk, docker inspection, cd navigation)

This incremental approach means permissions were granted just-in-time as tools became necessary, minimizing blast radius if a compromised session occurred.

Workflow Execution

The complete charter readiness workflow:

# 1. Fetch calendar events
jada-cli calendar fetch --weekend --date 2026-05-29

# 2. Generate manifests from event metadata
jada-ops generate-manifest --charter quinn-male --output /tmp/quinn-male-manifest.html

# 3. Extract trip sheet details from calendar payment metadata
jada-ops extract-trip-sheet --charter quinn-male --output /tmp/quinn-male-trip-sheet.html

# 4. Publish to S3 with CloudFront invalidation
aws s3 cp /tmp/quinn-male-manifest.html \
  s3://shipcaptaincrew-docs/manifests/2026-05-29-quinn-male-manifest.html \
  --metadata "charter=quinn-male,date=2026-05-29"

aws cloudfront create-invalidation --distribution-id [DIST_ID] \
  --paths "/manifests/*" "/trip-sheets/*"

# 5. Generate readiness report
jada-ops report generate --output weekend-charters-readiness-2026-05-29.md

What's Next

The foundation is in place for several expansions: