SpecSync: Keeping Code and Contracts in Sync

The Problem That Inspired Us

We've all been there: you commit code that looks perfect, tests pass, CI is green—but three days later, someone discovers your new endpoint isn't documented, your API call targets a non-existent backend route, or your tests don't actually cover the feature you just shipped.

Drift happens. And it happens silently.

Even worse, in microservices architectures, drift happens across repositories. Your frontend team updates their API calls, but the backend team changed the endpoint signature last week. Nobody knows until production breaks.

I built SpecSync to solve this at the source: at commit time, before drift enters your codebase.


What I Built

SpecSync is a two-part system that leverages Kiro's Model Context Protocol (MCP) to provide intelligent, automated validation:

Part 1: SpecSync Core - Single-Repo Validation

A commit-time validation system that ensures:

  • Specs define what you're building
  • Code implements the spec
  • Tests verify the implementation
  • Docs explain the API

When you commit, SpecSync validates all four are aligned. If they're not, it either:

  • Blocks the commit (strict mode)
  • Generates remediation tasks (task mode)
  • Auto-fixes drift (semi-auto mode with Kiro)

Part 2: Bridge - Cross-Repo Contract Sync

A git-based contract synchronization system that:

  • Extracts API contracts from provider repos (backends)
  • Syncs contracts to consumer repos (frontends) via git
  • Validates API calls against cached contracts
  • Detects drift before integration breaks

Bridge works offline (uses cached contracts) and syncs in parallel (multiple dependencies at once).


How I Built It

Architecture

┌─────────────────────────────────────────────────────────┐
│                    Kiro (MCP Client)                    │
└─────────────────────────────────────────────────────────┘
                           │
                           │ MCP Protocol
                           ▼
┌─────────────────────────────────────────────────────────┐
│              SpecSync MCP Server (TypeScript)           │
│  Tools: git_get_staged_diff, bridge_*, validate_*      │
└─────────────────────────────────────────────────────────┘
                           │
                ┌──────────┴──────────┐
                ▼                     ▼
    ┌───────────────────┐   ┌──────────────────┐
    │  SpecSync Core    │   │  Bridge System   │
    │  (Python)         │   │  (Python)        │
    │                   │   │                  │
    │  • Validator      │   │  • Extractor     │
    │  • Drift Detector │   │  • Sync Engine   │
    │  • Test Analyzer  │   │  • Drift Detector│
    │  • Doc Analyzer   │   │  • CLI           │
    └───────────────────┘   └──────────────────┘

Key Technologies

MCP Integration:

  • Built custom MCP server in TypeScript using @modelcontextprotocol/sdk
  • Exposed 9 tools to Kiro for validation and contract sync (including bridge_auto_sync)
  • Enabled Kiro to orchestrate complex validation workflows

Python Backend:

  • AST parsing for code analysis (endpoints, API calls, models)
  • YAML for contract serialization
  • Git subprocess for cross-repo sync
  • ThreadPoolExecutor for parallel sync (max 5 concurrent)
  • Hypothesis for property-based testing

Validation Logic:

  • Steering rules (.kiro/steering/rules.md) define correlation patterns
  • File correlation: backend/handlers/*.py.kiro/specs/app.yaml
  • Multi-analyzer architecture: drift, test coverage, documentation
  • Configurable blocking vs. task generation

Bridge Sync:

  • Git-based: git clone --depth 1 for efficiency
  • Offline fallback: uses cached contracts when sync fails
  • Contract diff: detects added/removed/modified endpoints
  • Auto-detection: scans code to determine provider vs. consumer role
  • Auto-sync: configurable intervals with silent mode and notifications
  • Interactive wizard: one-command setup with auto-detection and guided prompts

What I Learned

1. MCP is Powerful for Agentic Workflows

By exposing validation as MCP tools, I let Kiro:

  • Decide when to validate (pre-commit, on-demand, etc.)
  • Orchestrate complex workflows (sync → validate → fix)
  • Provide context-aware suggestions

This is way more flexible than a rigid git hook.

2. Property-Based Testing Catches Edge Cases

I used Hypothesis to generate random contracts, endpoints, and configurations. This caught bugs I never would have found with example-based tests:

  • Duplicate endpoint handling
  • Unicode in contract paths
  • Empty endpoint lists
  • Concurrent sync race conditions

3. Offline-First Design Matters

Bridge caches contracts locally, so validation works even when:

  • Network is down
  • Dependency repo is private
  • CI environment has no git access

This made the system way more reliable.

4. Cross-Repo Sync is Hard

Challenges I solved:

  • Temporary directory cleanup: Used try/finally to ensure cleanup even on failure
  • Parallel sync deadlocks: Limited to 5 concurrent syncs
  • Git credential handling: Relied on system git config (no credential storage)
  • Contract versioning: Used timestamps and diff detection

Challenges I Faced

Challenge 1: AST Parsing Complexity

Problem: FastAPI uses decorators like @app.get("/users"), but I also needed to support @router.get, async functions, and various parameter types.

Solution: Built a flexible AST walker that handles:

  • Both FunctionDef and AsyncFunctionDef
  • Multiple decorator patterns (app, router, api, blueprint)
  • Type annotations for parameters and return types

Challenge 2: Git Operations in Python

Problem: Python's subprocess for git is error-prone (encoding issues, timeouts, cleanup).

Solution:

  • Used capture_output=True, text=True, encoding='utf-8', errors='replace'
  • Implemented timeout (60s) and retry logic
  • Shallow clones (--depth 1) for speed
  • Proper temp directory cleanup with shutil.rmtree

Challenge 3: Making Validation Non-Blocking

Problem: Developers hate blocked commits. But I need to catch drift.

Solution: Three modes:

  1. Blocking mode: Fail commit on drift (strict teams)
  2. Task mode: Generate .kiro/specs/*/remediation-tasks.md (flexible teams)
  3. Semi-auto mode: Kiro fixes drift automatically after commit (AI-assisted teams)

Configurable via .kiro/settings/specsync.json.

Challenge 4: Language Support Scope

Problem: Supporting multiple languages (Python, TypeScript, Go, Java) would require different AST parsers, framework patterns, and testing strategies.

Solution:

  • Focused on Python first to deliver a working system within the hackathon timeline
  • Built extensible architecture that makes adding languages straightforward
  • Python covers FastAPI, Flask, Django—a large portion of modern APIs
  • Roadmap includes TypeScript/JavaScript (Express, NestJS) as next priority

This trade-off let us build a complete, tested system rather than a half-working multi-language prototype.

Challenge 5: Testing Cross-Repo Sync

Problem: Hard to test git-based sync without real repos.

Solution:

  • Integration tests use temporary git repos
  • Mock git operations for unit tests
  • Property-based tests for contract diff logic
  • Manual testing checklist for end-to-end validation

Technical Highlights

Property-Based Test Example

from hypothesis import given, strategies as st

@given(
    old_contract=contract_strategy(),
    new_contract=contract_strategy()
)
def test_contract_diff_is_symmetric(old_contract, new_contract):
    """Property: Diff should detect all changes between any two contracts."""
    diff = compare_contracts(old_contract, new_contract)

    # If contracts are identical, diff should be empty
    if old_contract == new_contract:
        assert not diff.has_changes()

    # All endpoints should be accounted for
    total_changes = (
        len(diff.added_endpoints) + 
        len(diff.removed_endpoints) + 
        len(diff.modified_endpoints)
    )
    assert total_changes >= 0

MCP Tool Implementation

case "bridge_sync": {
  const dep = (args as any)?.dependency || "";
  return this.runBridgeCommand(`sync ${dep}`);
}

private runBridgeCommand(command: string) {
  try {
    const output = execSync(`specsync-bridge ${command}`, {
      encoding: "utf-8",
      timeout: 60000,
      cwd: process.cwd(),
    });
    return { content: [{ type: "text", text: output }] };
  } catch (error: any) {
    return {
      content: [{ type: "text", text: `Error: ${error.message}` }],
      isError: true,
    };
  }
}

Parallel Sync with Progress

with ThreadPoolExecutor(max_workers=5) as executor:
    future_to_dep = {
        executor.submit(self._sync_with_progress, dep): dep
        for dep in dependency_names
    }
    for future in as_completed(future_to_dep):
        result = future.result()
        results.append(result)

Results

Test Coverage

  • 230 tests total (unit, integration, property-based)
  • 107 bridge-specific tests (all passing)
  • 100+ property-based test iterations per property

Performance

  • Contract extraction: < 1s for typical repo
  • Sync (first time): 2-5s per dependency
  • Sync (cached): < 1s per dependency
  • Validation: < 2s for typical codebase
  • Parallel sync: O(slowest dependency) not O(sum)

Features Delivered

  • ✅ Commit-time validation (spec-code-test-doc)
  • ✅ Cross-repo contract sync via git
  • ✅ Drift detection (missing endpoints, parameter mismatches)
  • ✅ Auto-detection (provider vs. consumer)
  • ✅ Offline fallback (cached contracts)
  • ✅ Parallel sync (multiple dependencies)
  • Auto-sync (configurable intervals: 30min, 1h, 2h, 3h, 6h)
  • Interactive setup wizard (one-command onboarding)
  • ✅ MCP integration (9 tools for Kiro)
  • ✅ CLI (specsync-bridge command)
  • ✅ Pip-installable package (PyPI)
  • ✅ NPM-installable MCP server

What's Next

Short Term

  • Support for GraphQL and gRPC contracts
  • TypeScript/JavaScript endpoint extraction
  • Breaking change impact analysis
  • Visual dependency graphs
  • Webhook support for instant contract updates

Long Term

  • Contract versioning and compatibility checking
  • Automated migration suggestions
  • IDE plugins for inline drift warnings
  • Response schema validation (beyond endpoint matching)
  • Slack/Discord notifications for breaking changes

Try It Yourself

# Install
pip install specsync-bridge

# Provider repo
specsync-bridge detect          # Auto-detect role
specsync-bridge init --role provider
specsync-bridge extract         # Extract contract
git add .kiro/contracts/provided-api.yaml
git commit -m "Add API contract"

# Consumer repo
specsync-bridge init --role consumer
specsync-bridge add-dependency backend --git-url <url>
specsync-bridge sync            # Fetch contract
specsync-bridge validate        # Check for drift

Conclusion

SpecSync proves that drift is preventable. By validating at commit time and syncing contracts across repos, I catch misalignment before it becomes a bug.

The combination of MCP integration (for Kiro orchestration) and git-based sync (for cross-repo contracts) creates a system that's both powerful and practical.

Drift monsters, meet your match. 🐉⚔️


Built With

Languages:

  • Python 3.9+ (backend, validation, CLI)
  • TypeScript (MCP server)

Frameworks & Libraries:

  • FastAPI (example API)
  • Model Context Protocol SDK (@modelcontextprotocol/sdk)
  • Hypothesis (property-based testing)
  • pytest (testing framework)
  • PyYAML (contract serialization)

Tools & Platforms:

  • Git (contract sync)
  • Kiro IDE (MCP client)
  • GitHub (version control)
  • pip (package distribution)

Key Technologies:

  • AST parsing (ast module)
  • Subprocess management (subprocess, ThreadPoolExecutor)
  • MCP (Model Context Protocol)
  • Property-based testing
  • Git hooks (pre-commit validation)

Testing:

  • pytest (unit & integration tests)
  • Hypothesis (property-based tests)
  • 230 total tests, 100% passing

Built With

Share this project:

Updates