Skip to content

Nafsgerman/slack-legacy-modernization-commander

Repository files navigation

Legacy Modernization Commander

Slack-native command center for enterprise legacy modernization teams.

Built by a modernization practitioner with 22 years across COBOL, OLTP, and mainframe legacy estates. This is the operator's view of where migration programs actually break — not in code conversion, but in the coordination of business rules, dependencies, and SME validation that conversion silently assumes is already done.

Legacy Modernization Commander turns a legacy module into a business-readable modernization assessment inside Slack: what the module does, which business rules it encodes, where migration risk concentrates, what SMEs must validate, and which work packages should move next. Built for the Slack Agent Builder Challenge as a focused, portfolio-grade agentic workflow.

Hackathon technology requirement: MCP server integration. Legacy analysis is exposed as an MCP server (src/mcp/server.ts) over stdio; the Slack app consumes it as an MCP client (src/domain/mcp-legacy-analysis-client.ts). Details below.

Demo command

/legacy assess claims-batch

Returns a structured modernization assessment for a synthetic COBOL claims-batch module (CLAIMS-BATCH, z/OS batch, insurance claims adjudication).

Three modes

The command runs in one of three modes:

Mode Invocation Behavior
Auto /legacy assess claims-batch Agent if ANTHROPIC_API_KEY is set, otherwise fixture.
Agent /legacy assess claims-batch --agent Live Claude grounding (claude-sonnet-4-6) against real COBOL source, via MCP.
Fixture /legacy assess claims-batch --fixture Deterministic local fixture. No model call.

Auto mode means the demo always works — with a key it grounds live; without one it falls back to a deterministic assessment of the same shape.

MCP server integration

Legacy analysis is not embedded in the Slack app. It is a standalone MCP server that the Slack app talks to as a client over stdio.

src/mcp/server.ts      MCP server — McpServer + StdioServerTransport
src/mcp/tools.ts       Tool implementations exposed over MCP
src/domain/mcp-legacy-analysis-client.ts
                       MCP client — Client + StdioClientTransport,
                       implements LegacyAnalysisClient

Run the server standalone:

npm run mcp:server

Tools exposed over MCP

The server (legacy-modernization-commander-mcp) registers three tools:

Tool Purpose
legacy.assess_module Resolve a legacy module and return business purpose, modernization risk, dependencies, and SME questions.
legacy.extract_rules Extract candidate business rules from a legacy module assessment source.
legacy.create_plan Create migration path steps and ticket-draft work packages for a legacy module.

Each tool takes a moduleId and returns structured JSON. These three map directly onto the LegacyAnalysisClient interface the Slack app depends on — MCP is the transport, not a bolt-on.

This matters architecturally, not just for compliance: the Slack app depends on the LegacyAnalysisClient interface, and MCP is one implementation of it. A production deployment can point the same client at a real code-analysis backend without touching the Slack workflow layer.

The architectural boundary

This is the point of the project.

The agent proposes a grounded assessment. The deterministic application layer owns SME validation state.

Every claim the agent produces — risk level, each business rule, each work package — is stamped machine_inferred or sme_required. The model has no path to sme_validated. That status can only be reached through the application's SME validation workflow, and the type system enforces it: the agent's output type cannot express a validated claim. This is covered by adversarial tests that assert the model can never emit or escalate to a validated state.

The App Home dashboard reflects validated workflow state, not raw model output. Model-proposes / app-validates is enforced at the type level, not by convention.

How grounding works (agent mode)

  1. The model is given the real source (src/demo/source/claims-batch.cbl) and proposes citations — paragraph and line references — for each rule and risk it asserts.
  2. verifyAndStamp (pure, no model in the loop) resolves each proposed reference against the actual source lines.
  3. Resolved references mint catalog evidence (EV-###) in the EvidenceCatalog, each carrying a file/paragraph/line locator and the real excerpt.
  4. Each claim is assigned a validationStatus. A claim whose citation does not resolve does not get to stand as grounded.

Every assertion in the assessment traces to a row in the evidence catalog. No catalog reference, no claim.

Derived SME checklist

The model never emits a validation checklist. The application derives the smeValidationChecklist from the model's unknowns. This keeps the agent in its lane (surfacing what it doesn't know) and the application in its lane (owning the workflow that resolves it).

Interactive Slack loop

The assessment is not a one-shot report. It is the entry point to a workflow.

The assessment card carries action buttons:

  • Mark reviewed
  • SME follow-up
  • Draft ticket
  • Show trace

Each SME decision updates the App Home live dashboard and posts a refreshed traceability graph (PNG) to the demo channel. The dashboard tracks validation state across the assessment as SMEs work through it — the workflow surface, not a static document.

What is real vs. synthetic

Honest framing is a hard rule in this repo. Every claim maps to a visible artifact.

  • Real: the MCP server and client, the agent grounding loop, citation verification against actual source lines, the evidence catalog, the type-enforced validation boundary, the interactive SME workflow, the traceability graph.
  • Synthetic and clearly labeled: the CLAIMS-BATCH module and its source are a representative synthetic COBOL artifact, not customer code.
  • Not claimed: production-grade COBOL parsing, live enterprise-system integration, or automatic ticket creation. Work packages are drafts for human review — nothing is filed in Jira.

Outputs are grounded, traceable, and reviewable. They are an input to SME validation, not a substitute for it.

Architecture

flowchart TB
  subgraph slack["Slack surface — src/app/"]
    cmd["/legacy assess claims-batch<br/>· auto · --agent · --fixture"]
    card["Assessment card + action buttons<br/>Mark reviewed · SME follow-up · Draft ticket · Show trace"]
    home["App Home dashboard<br/>+ traceability graph PNG → demo channel"]
  end

  subgraph domain["Orchestration — src/domain/"]
    orch["orchestrator.ts"]
    factory["client-factory.ts<br/>auto = agent if ANTHROPIC_API_KEY, else fixture"]
    fixture["fixture client<br/>deterministic prebuilt assessment"]
  end

  subgraph proposes["MODEL PROPOSES (untrusted) — over MCP"]
    mcpclient["mcp-legacy-analysis-client.ts<br/>MCP client · stdio"]
    mcpserver["src/mcp/server.ts<br/>legacy.assess_module · legacy.extract_rules · legacy.create_plan"]
    agent["claude-sonnet-4-6 grounding loop"]
    cbl[("src/demo/source/claims-batch.cbl<br/>synthetic COBOL source")]
  end

  subgraph validates["APP VALIDATES (deterministic, pure)"]
    ground["grounding.ts · verifyAndStamp<br/>resolve citations → mint EV-### → stamp status"]
    catalog[["EvidenceCatalog<br/>every claim ↔ EV-### ↔ real line"]]
    decision["validation-decision.ts<br/>SME workflow — only path to sme_validated"]
  end

  cmd --> orch --> factory
  factory -->|agent mode| mcpclient
  factory -->|fixture mode| fixture
  mcpclient <-->|MCP stdio| mcpserver
  mcpserver --> agent
  cbl --- agent
  agent -->|proposed citations| ground
  ground --> catalog
  ground -->|machine_inferred / sme_required| card
  fixture --> card
  card -->|SME decision| decision
  decision -->|sme_validated / rejected| home
  catalog -.->|trace refs| home

  style proposes fill:#fff4e5,stroke:#b26a00,color:#5c3d00
  style validates fill:#e8f0fe,stroke:#1a73e8,color:#0b3d91
  style cbl fill:#fef7e0,stroke:#b26a00
  style decision fill:#d2e3fc,stroke:#1a73e8
Loading

The LegacyAnalysisClient boundary lets a production version swap the MCP-backed agent for a real code-analysis backend, dependency mapper, or ticketing system without touching the Slack workflow layer.

Setup

Install:

npm install

Required environment variables (.env, never committed):

SLACK_BOT_TOKEN=xoxb-...
SLACK_SIGNING_SECRET=...
SLACK_APP_TOKEN=xapp-...
PORT=3000
NODE_ENV=development

Optional — enables agent mode:

ANTHROPIC_API_KEY=sk-ant-...

Run

Deterministic local demo (no Slack, no key):

npm run demo

Slack app (Socket Mode):

npm run slack:dev

MCP server standalone:

npm run mcp:server

Slash command setup, scopes, and Socket Mode configuration: see docs/SLACK_SETUP.md.

Test

npm test

Type check only:

npm run typecheck

Full CI gate (typecheck + tests):

npm run ci

CI runs tsc --noEmit before the test suite. Type-stripping at runtime can let tests pass while TypeScript is broken, so the type check is a required gate, not an afterthought.

Repository layout

docs/          Product, architecture, demo, and submission notes
slack/         Slack app manifest
src/app/       Slack entry points, rendering, App Home, action handlers
src/mcp/       MCP server and tool implementations
src/domain/    Assessment types, orchestration, MCP + fixture clients
src/demo/      Synthetic source and deterministic fixtures
tests/         Unit, behavior, and adversarial boundary tests

License

MIT

About

Slack-native command center for enterprise legacy modernization teams.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors