Sync Contracts

> Lightweight incremental update of workspace contracts without full re-analysis.

Published by @alinaqi·from alinaqi/maggy·0 agent reads / 30d·0 saves·

/sync-contracts

Lightweight incremental update of workspace contracts without full re-analysis.

Purpose

Fast contract synchronization that:

  • Checks only contract source files (not full workspace)
  • Updates CONTRACTS.md with changes
  • Validates consistency
  • Takes ~15 seconds instead of ~2 minutes

When to Use

ScenarioCommand
After modifying API endpoints/sync-contracts
After changing shared types/sync-contracts
Session start shows stale contracts/sync-contracts
Post-commit hook (automatic)/sync-contracts --lightweight
Before pushing changes/sync-contracts --validate
See what changed without updating/sync-contracts --diff

Behavior

Step 1: Load Existing Topology

🔄 Loading workspace context...

Workspace: myapp (Monorepo)
Last full analysis: 2026-01-18T10:00:00Z
Last sync: 2026-01-20T14:32:00Z

Does NOT re-discover workspace structure - uses existing TOPOLOGY.md.

Step 2: Check Contract Sources

📋 Checking contract sources...

Monitored files (from .contract-sources):
  ✓ apps/api/openapi.json (modified 2h ago)
  ✓ packages/shared-types/src/index.ts (modified 2h ago)
  ○ packages/db/schema/campaigns.ts (unchanged)
  ○ packages/db/schema/users.ts (unchanged)
  ○ apps/api/app/schemas/campaign.py (unchanged)

Changes detected: 2 files

Step 3: Extract Changes

📝 Extracting contract changes...

apps/api/openapi.json:
  + POST /api/campaigns/bulk (new endpoint)
  ~ GET /api/campaigns (added 'status' query param)

packages/shared-types/src/index.ts:
  ~ Campaign interface (added 'tags: string[]' field)
  + CampaignBulkCreate interface (new)

Step 4: Update Artifacts

✏️  Updating workspace artifacts...

Updated: _project_specs/workspace/CONTRACTS.md
  - Added POST /api/campaigns/bulk to endpoints
  - Updated Campaign type definition
  - Added CampaignBulkCreate type

Updated: _project_specs/workspace/CROSS_REPO_INDEX.md
  - Added bulk create capability

Timestamps updated:
  Last sync: 2026-01-20T16:45:00Z

Step 5: Validate Consistency

✅ Validating contract consistency...

Checks:
  ✓ OpenAPI endpoint count matches routes (48/48)
  ✓ All Pydantic models have TypeScript equivalents
  ✓ No orphaned types in shared-types
  ⚠️  Frontend types may need regeneration

Validation: PASSED (1 warning)

Final Output

════════════════════════════════════════════════════════════════
  CONTRACT SYNC COMPLETE
════════════════════════════════════════════════════════════════

Sources checked: 5
Changes detected: 2
Files updated: 2

Changes Summary:
  + POST /api/campaigns/bulk (new endpoint)
  ~ Campaign interface (added 'tags' field)
  + CampaignBulkCreate interface (new)

Freshness: 🟢 Fresh
Last sync: 2026-01-20T16:45:00Z

⚠️  Note: Frontend types may need regeneration
   Run: cd apps/web && npm run generate:types

════════════════════════════════════════════════════════════════

Flags

FlagDescription
--lightweightSkip validation, minimal output (for hooks)
--diffShow changes without updating files
--validateOnly validate, don't update
--forceUpdate even if no changes detected
--verboseShow detailed extraction output

Diff Mode

Preview changes without applying:

/sync-contracts --diff

Output:

📋 Contract Changes (not applied)

apps/api/openapi.json:
  + POST /api/campaigns/bulk
    Request: CampaignBulkCreate[]
    Response: Campaign[]

  ~ GET /api/campaigns
    + query param: status (string, optional)

packages/shared-types/src/index.ts:
  ~ interface Campaign {
      id: string;
      name: string;
  +   tags: string[];        // NEW
      status: CampaignStatus;
    }

  + interface CampaignBulkCreate {
      campaigns: CampaignCreate[];
    }

To apply these changes: /sync-contracts

Validate Mode

Check consistency without updating:

/sync-contracts --validate

Output:

🔍 Contract Validation

Endpoint Consistency:
  ✓ OpenAPI spec: 48 endpoints
  ✓ Route files: 48 handlers
  ✓ Match: YES

Type Consistency:
  ✓ Pydantic models: 23
  ✓ TypeScript types: 34
  ✓ Shared types exported: 34
  ⚠️  2 types only in backend (internal)

Cross-Module References:
  ✓ Frontend imports valid types: YES
  ✓ Backend codegen up to date: YES

Overall: ✅ VALID (2 warnings)

Lightweight Mode

For hooks - minimal output, fast execution:

/sync-contracts --lightweight

Output:

✓ Contracts synced (2 changes)

Or if no changes:

✓ Contracts up to date

Contract Sources File

The sync uses .contract-sources to know what to check:

# _project_specs/workspace/.contract-sources
# Auto-generated by /analyze-workspace
# Edit to add/remove monitored files

# OpenAPI specs
apps/api/openapi.json

# Type definitions
packages/shared-types/src/index.ts
packages/shared-types/src/api.ts
packages/shared-types/src/campaign.ts

# Pydantic schemas (Python)
apps/api/app/schemas/campaign.py
apps/api/app/schemas/user.py
apps/api/app/schemas/auth.py

# Database schema
packages/db/schema/campaigns.ts
packages/db/schema/users.ts

To add a new source:

echo "apps/api/app/schemas/new_model.py" >> _project_specs/workspace/.contract-sources

Error Handling

No Contract Sources

⚠️  No contract sources configured

Run /analyze-workspace first to set up contract monitoring.

Source File Missing

⚠️  Contract source not found: apps/api/openapi.json

Options:
  1. Generate it: cd apps/api && python -m app.generate_openapi
  2. Remove from monitoring: Edit .contract-sources
  3. Skip this file: /sync-contracts --skip apps/api/openapi.json

Validation Failed

❌ Contract validation failed

Issues found:
  1. OpenAPI has 48 endpoints, routes have 47
     Missing: DELETE /api/campaigns/:id (in spec, not in routes)

  2. Type mismatch: Campaign.status
     OpenAPI: "draft" | "active" | "paused"
     TypeScript: "draft" | "active" | "paused" | "archived"

Fix these issues, then run /sync-contracts again.
Or force update: /sync-contracts --force

Integration with Hooks

Post-Commit Hook

Automatically runs after commits that touch contract sources:

# hooks/post-commit
CONTRACT_SOURCES=$(cat _project_specs/workspace/.contract-sources 2>/dev/null)
COMMITTED=$(git diff-tree --no-commit-id --name-only -r HEAD)

for source in $CONTRACT_SOURCES; do
  if echo "$COMMITTED" | grep -q "$source"; then
    echo "📝 Contract source changed, syncing..."
    claude --silent "/sync-contracts --lightweight"
    break
  fi
done

Pre-Push Hook

Validates before push:

# hooks/pre-push
echo "🔍 Validating contracts..."
claude --silent "/sync-contracts --validate"

if [ $? -ne 0 ]; then
  echo "❌ Contract validation failed"
  echo "Run /sync-contracts to fix"
  exit 1
fi

Comparison: sync-contracts vs analyze-workspace

Aspect/sync-contracts/analyze-workspace
Time~15 seconds~2 minutes
ScopeContract files onlyFull workspace
Discovers new modulesNoYes
Updates TOPOLOGY.mdNoYes
Updates CONTRACTS.mdYesYes
Rebuilds dependency graphNoYes
When to useFrequent (daily)Occasional (weekly)

More on the bench

SKILL▲0

Micro SaaS Launcher

Expert in launching small, focused SaaS products fast - the indie hacker approach to building profitable software. Covers idea validation, MVP development, pricing, launch strategies, and growing to sustainable revenue. Ship in weeks, not months.

ai-prompt-engineering+3
⊙ 43
SKILL▲0

Security Compliance Compliance Check

You are a compliance expert specializing in regulatory requirements for software systems including GDPR, HIPAA, SOC2, PCI-DSS, and other industry standards. Perform comprehensive compliance audits and provide implementation guidance for achieving and maintaining compliance.

ai-prompt-engineering+3
⊙ 40
SKILL▲0

Skill Creator

Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.

ai-prompt-engineering+1
⊙ 40