# Formatter Code Structure Analysis
**Session ID:** style-alignment-formatters
**Agent:** formatter-explorer
**Date:** 2026-02-13
**Task:** Analyze formatter code structure and output patterns for STYLE.md compliance audit
---
## Executive Summary
The synapse-mcp project uses a domain-organized formatter architecture with 11 formatter files spread across 6 domains. All formatters produce markdown output with varying levels of STYLE.md compliance. Key findings:
- **Total Formatters:** 27 functions across 6 domains
- **STYLE.md Compliance:** Partial (symbols inconsistent, missing legends, no timestamp support)
- **Architecture:** Strategy pattern with domain-specific modules
- **Output Format:** Markdown-first with JSON fallback
---
## Directory Structure
```
src/formatters/
├── index.ts # Barrel export, re-exports all formatters
├── strategy.ts # Strategy pattern (IFormatter, MarkdownFormatter, JSONFormatter)
├── utils.ts # Shared utilities (truncateIfNeeded)
├── container.ts # Container operations (7 formatters)
├── compose.ts # Compose operations (2 formatters)
├── docker.ts # Docker system operations (6 formatters)
├── host.ts # Host operations (3 formatters)
├── scout.ts # SSH/Scout operations (6 formatters)
└── diagnostics.ts # Health checks (1 formatter)
```
---
## Formatter Inventory by Domain
### 1. Container Formatters (`container.ts`)
| Function | Actions | Current Symbols | STYLE.md Compliant |
|----------|---------|----------------|-------------------|
| `formatContainersMarkdown` | `flux:container:list` | 🟢🟡🔴 | ❌ (missing legend line) |
| `formatLogsMarkdown` | `flux:container:logs` | None | ❌ (missing preview format) |
| `formatStatsMarkdown` | `flux:container:stats` | None | ❌ (missing trend symbols) |
| `formatMultiStatsMarkdown` | `flux:container:stats` (all) | None | ❌ (missing trend symbols) |
| `formatInspectMarkdown` | `flux:container:inspect` | None | ❌ (missing summary box) |
| `formatInspectSummaryMarkdown` | `flux:container:inspect` | None | ⚠️ (partial compliance) |
| `formatSearchResultsMarkdown` | `flux:container:search` | 🟢🟡🔴 | ❌ (missing legend line) |
**Symbols Used:** 🟢 (running), 🟡 (paused), 🔴 (stopped)
**STYLE.md Required:** ● (running), ◐ (partial), ○ (stopped)
**Key Issues:**
- Using emoji instead of canonical symbols (🟢 vs ●)
- No legend lines for mixed state outputs
- Missing timestamp support for volatile data (stats, logs)
- No trend symbols for stats (↗↘→)
- Port overflow uses `,` instead of `+N` notation
### 2. Compose Formatters (`compose.ts`)
| Function | Actions | Current Symbols | STYLE.md Compliant |
|----------|---------|----------------|-------------------|
| `formatComposeListMarkdown` | `flux:compose:list` | 🟢🟡🔴 | ❌ (missing legend) |
| `formatComposeStatusMarkdown` | `flux:compose:status` | 🟢🔴 | ❌ (missing legend) |
**Symbols Used:** 🟢 (running), 🟡 (partial), 🔴 (stopped)
**STYLE.md Required:** ● (running), ◐ (partial), ○ (stopped)
**Key Issues:**
- Using emoji instead of canonical symbols
- No legend lines in output
- Services preview shows `join(", ")` instead of `[N] service1,service2…` format
- Missing status breakdown summary line
### 3. Docker System Formatters (`docker.ts`)
| Function | Actions | Current Symbols | STYLE.md Compliant |
|----------|---------|----------------|-------------------|
| `formatDockerInfoMarkdown` | `flux:docker:info` | ❌ | ❌ (missing summary box) |
| `formatDockerDfMarkdown` | `flux:docker:df` | None | ⚠️ (partial compliance) |
| `formatPruneMarkdown` | `flux:docker:prune` | None | ⚠️ (partial compliance) |
| `formatImagesMarkdown` | `flux:docker:images` | None | ❌ (missing summary) |
| `formatNetworksMarkdown` | `flux:docker:networks` | None | ❌ (missing summary) |
| `formatVolumesMarkdown` | `flux:docker:volumes` | None | ❌ (missing summary) |
**Symbols Used:** ❌ (error only)
**STYLE.md Required:** Various (✓✗⚠)
**Key Issues:**
- No summary lines for lists
- Missing proper error formatting (should use `✗ Operation failed...`)
- No pagination support in some formatters
- Missing count summaries
### 4. Host Formatters (`host.ts`)
| Function | Actions | Current Symbols | STYLE.md Compliant |
|----------|---------|----------------|-------------------|
| `formatHostStatusMarkdown` | `flux:host:status` | 🟢🔴 | ❌ (using emoji) |
| `formatHostResourcesMarkdown` | `flux:host:resources` | ❌ | ❌ (missing trends, warnings) |
| `formatHostPortsMarkdown` | `flux:host:ports` | 🐳🔵🖥️🟢🔵⚪ | ❌ (inconsistent symbols) |
**Symbols Used:** 🟢🔴 (status), 🐳🔵🖥️ (source types), 🟢🔵⚪ (states)
**STYLE.md Required:** ✓✗ (status), canonical source symbols, ●◐○ (states)
**Key Issues:**
- Port formatter uses unique emoji set not aligned with STYLE.md
- Resources missing threshold warnings (disk >85%, memory >90%, CPU >90%)
- Resources missing trend symbols (↗↘→)
- Missing timestamp for volatile data (resources, uptime)
### 5. Scout Formatters (`scout.ts`)
| Function | Actions | Current Symbols | STYLE.md Compliant |
|----------|---------|----------------|-------------------|
| `formatScoutReadMarkdown` | `scout:peek` | 📄⚠️ | ❌ (using emoji) |
| `formatScoutListMarkdown` | `scout:peek` (dir) | 📁 | ❌ (using emoji) |
| `formatScoutTreeMarkdown` | `scout:peek` (tree) | 🌳 | ❌ (using emoji) |
| `formatScoutExecMarkdown` | `scout:exec` | ✅❌ | ⚠️ (partial compliance) |
| `formatScoutFindMarkdown` | `scout:find` | 🔍 | ❌ (using emoji) |
| `formatScoutTransferMarkdown` | `scout:beam` | 📦⚠️ | ❌ (using emoji) |
| `formatScoutDiffMarkdown` | `scout:delta` | 📊 | ❌ (using emoji) |
**Symbols Used:** Various emoji
**STYLE.md Required:** Text-based symbols (✓✗⚠ℹ)
**Key Issues:**
- Heavy emoji usage instead of canonical symbols
- Exec formatter uses ✅❌ instead of ✓✗
- Missing summary lines
- No pagination support in find/list operations
### 6. Diagnostics Formatters (`diagnostics.ts`)
| Function | Actions | Current Symbols | STYLE.md Compliant |
|----------|---------|----------------|-------------------|
| `formatHostDoctorMarkdown` | `flux:host:doctor` | 🏥✅⚠️❌ | ⚠️ (mostly compliant) |
**Symbols Used:** 🏥 (title), ✅⚠️❌ (status)
**STYLE.md Required:** ✓⚠✗
**Key Issues:**
- Using emoji (✅❌) instead of text symbols (✓✗)
- Overall status uses emoji instead of symbols
- Missing rollup summary in standard format
---
## Symbol Mapping Analysis
### Current Symbol Usage
| Domain | Running/OK | Partial/Warn | Stopped/Fail | Notes |
|--------|-----------|--------------|--------------|-------|
| Container | 🟢 | 🟡 | 🔴 | Emoji circles |
| Compose | 🟢 | 🟡 | 🔴 | Same as container |
| Host Status | 🟢 | — | 🔴 | No partial state |
| Host Ports | 🟢🔵⚪ | — | — | Unique system |
| Scout | ✅ | — | ❌ | Checkmarks |
| Diagnostics | ✅ | ⚠️ | ❌ | Medical + checks |
### STYLE.md Required Symbols
| Category | Symbol | Usage | Replacement Needed |
|----------|--------|-------|-------------------|
| Running/Active | ● | Status indicator | Replace 🟢 |
| Partial/Degraded | ◐ | Status indicator | Replace 🟡 |
| Stopped/Inactive | ○ | Status indicator | Replace 🔴 |
| Success/OK | ✓ | Result indicator | Replace ✅ |
| Failure/Error | ✗ | Result indicator | Replace ❌ |
| Warning | ⚠ | Alert indicator | Keep (already used) |
| Info | ℹ | Info note | Add (not currently used) |
| Mapping | → | Relationship | Add for port mappings |
| Truncation | … | Continuation | Add (currently not used) |
| Overflow | +N | Count overflow | Add for port/service lists |
| Unavailable | — | Missing value | Add (currently using "-" or "N/A") |
| Trend Up | ↗ | Metric increase | Add for stats |
| Trend Down | ↘ | Metric decrease | Add for stats |
| Trend Stable | → | No change | Add for stats |
---
## Handler → Formatter Mapping
### Flux Tool Handlers
| Handler | Action | Subaction | Formatter Called |
|---------|--------|-----------|-----------------|
| `container.ts` | container | list | `formatContainersMarkdown` |
| `container.ts` | container | search | `formatSearchResultsMarkdown` |
| `container.ts` | container | inspect | `formatInspectMarkdown` |
| `container.ts` | container | logs | `formatLogsMarkdown` |
| `container.ts` | container | stats | `formatStatsMarkdown` or `formatMultiStatsMarkdown` |
| `compose.ts` | compose | list | `formatComposeListMarkdown` |
| `compose.ts` | compose | status | `formatComposeStatusMarkdown` |
| `compose-handlers.ts` | compose | up/down/restart/recreate/build/pull | `formatComposeResult` (inline) |
| `docker.ts` | docker | info | `formatDockerInfoMarkdown` |
| `docker.ts` | docker | df | `formatDockerDfMarkdown` |
| `docker.ts` | docker | prune | `formatPruneMarkdown` |
| `docker.ts` | docker | images | `formatImagesMarkdown` |
| `docker.ts` | docker | networks | `formatNetworksMarkdown` |
| `docker.ts` | docker | volumes | `formatVolumesMarkdown` |
| `host.ts` | host | status | `formatHostStatusMarkdown` |
| `host.ts` | host | resources | `formatHostResourcesMarkdown` |
| `host.ts` | host | ports | `formatHostPortsMarkdown` |
| `host.ts` | host | doctor | `formatHostDoctorMarkdown` |
### Scout Tool Handlers
| Handler | Action | Subaction | Formatter Called |
|---------|--------|-----------|-----------------|
| `scout-simple.ts` | scout | peek (file) | `formatScoutReadMarkdown` |
| `scout-simple.ts` | scout | peek (dir) | `formatScoutListMarkdown` |
| `scout-simple.ts` | scout | exec | `formatScoutExecMarkdown` |
| `scout-simple.ts` | scout | find | `formatScoutFindMarkdown` |
| `scout-simple.ts` | scout | beam | `formatScoutTransferMarkdown` |
| `scout-simple.ts` | scout | delta | `formatScoutDiffMarkdown` |
**Note:** Some handlers inline simple formatters or return raw output without dedicated formatters.
---
## Architecture Patterns
### Strategy Pattern Implementation
Located in `src/formatters/strategy.ts`:
```typescript
interface IFormatter {
format(data: unknown): string;
}
class MarkdownFormatter implements IFormatter { ... }
class JSONFormatter implements IFormatter { ... }
function createFormatter(format: "markdown" | "json"): IFormatter { ... }
```
**Usage:**
- Handlers call `formatResponse(data, format, markdownFn)` helper
- Default format is markdown
- JSON format wraps markdown strings in `{ output, format }` object
- Enables future format extensibility (HTML, YAML, etc.)
### Barrel Export Pattern
`src/formatters/index.ts` re-exports all formatters:
- Simplifies imports in handlers
- Centralizes formatter interface
- Maintains backward compatibility
### Domain-Specific Organization
Each domain (container, compose, docker, host, scout) has dedicated formatter file:
- Clear separation of concerns
- Easy to locate formatter for a given action
- Prevents formatter file bloat
---
## Missing STYLE.md Features
### 1. Legend Lines
**Required by STYLE.md:** Include legend when mixed states appear
**Current State:** No formatters include legend lines
**Affected Formatters:**
- `formatContainersMarkdown` (mixed container states)
- `formatComposeListMarkdown` (mixed stack states)
- `formatComposeStatusMarkdown` (mixed service states)
- `formatSearchResultsMarkdown` (mixed container states)
**Example Required Output:**
```
Legend: ● running ◐ partial ○ stopped
```
### 2. Summary Lines
**Required by STYLE.md:** Compact summary with `|` separators
**Current State:** Some formatters have summaries, but inconsistent format
**Missing In:**
- Image lists (should show: `Showing N of M images | offset: X`)
- Network lists (should show: `Networks: N | Hosts: M`)
- Volume lists (should show: `Volumes: N | Hosts: M`)
**Example Required Output:**
```
Showing 20 of 41 containers | state: all
```
### 3. Timestamp Support
**Required by STYLE.md:** `As of (EST): HH:MM:SS | MM/DD/YYYY`
**Current State:** No formatters include timestamps
**Required For:**
- Container stats (volatile data)
- Container logs (volatile data)
- Host resources (volatile data)
- Host uptime (volatile data)
- Scout logs (volatile data)
### 4. Trend Symbols
**Required by STYLE.md:** `↗↘→` for metric changes
**Current State:** No formatters support trend symbols
**Required For:**
- Container stats (CPU, memory, network)
- Host resources (CPU, memory, disk)
**Example Required Output:**
```
CPU: 34% ↗
Memory: 61% ↘
```
### 5. Overflow Notation
**Required by STYLE.md:** `+N` for count overflow, `…` for truncation
**Current State:** Uses `,` or text descriptions
**Affected:**
- Port lists (should use `80,443+3` instead of `80,443,8080,8443,9000`)
- Service lists (should use `[3] svc1,svc2…` instead of full list)
### 6. Warning Thresholds
**Required by STYLE.md:** Auto-warnings for resource thresholds
**Current State:** No automatic warnings
**Required Rules:**
- Disk usage >85% => `⚠`
- Memory usage >90% => `⚠`
- CPU sustained >90% => `⚠`
**Example Required Output:**
```
⚠ Disk usage critical: /dev/sda1 at 92%
```
### 7. Severity-First Sorting
**Required by STYLE.md:** Sort by severity: `⚠/✗` → `◐` → `●` → `○`
**Current State:** Most formatters use default sorting (alphabetical or creation time)
**Affected:**
- Container lists
- Compose stack lists
- Compose service lists
---
## Shared Utilities Analysis
### `utils.ts`
**Function:** `truncateIfNeeded(text: string): string`
**Purpose:** Truncate output exceeding `CHARACTER_LIMIT` constant
**Current Implementation:**
```typescript
if (text.length <= CHARACTER_LIMIT) return text;
return `${text.slice(0, CHARACTER_LIMIT - 100)}\n\n... [Output truncated. ...]`;
```
**STYLE.md Compliance:** ⚠️ Partial
- Uses `...` instead of `…` (three dots vs ellipsis character)
- Message format not aligned with STYLE.md pagination footer
**Required Format:**
```
Showing X–Y of Z | next_offset: N
```
### `formatBytes` (from `services/docker/utils/formatters.js`)
**Purpose:** Convert bytes to human-readable format
**Current Output:** `"5.2 GB"`, `"512 MB"`, etc.
**STYLE.md Compliance:** ✓ Compliant
- Uses correct units (B, KB, MB, GB, TB)
- Follows rounding policy (1 decimal for GB/MB)
---
## Compliance Scoring
### Overall Compliance Score: 32/100
**Breakdown:**
| Category | Score | Details |
|----------|-------|---------|
| Symbol Usage | 10/25 | Using emoji instead of canonical symbols |
| Structure | 18/25 | Has headers/tables but missing summaries/legends |
| Formatting | 12/25 | Tables are aligned, but missing overflow/truncation patterns |
| Metadata | 0/15 | No timestamps, no trend symbols, no auto-warnings |
| Ordering | 2/10 | No severity-first sorting |
**High-Compliance Formatters (50%+):**
- `formatHostDoctorMarkdown` (65%) - has summary, checks, recommendations
- `formatInspectSummaryMarkdown` (55%) - structured table format
**Low-Compliance Formatters (<30%):**
- `formatScoutReadMarkdown` (20%) - heavy emoji usage
- `formatScoutFindMarkdown` (15%) - minimal structure
- `formatLogsMarkdown` (25%) - missing preview format
---
## Recommendations for Remediation
### Phase 1: Symbol Standardization (High Priority)
**Effort:** Low
**Impact:** High
1. Replace all emoji with canonical STYLE.md symbols:
- 🟢 → ●
- 🟡 → ◐
- 🔴 → ○
- ✅ → ✓
- ❌ → ✗
- Remove decorative emoji (📄📁🌳🔍📦📊🐳🔵🖥️⚪)
2. Update port formatter symbol system to use canonical symbols
**Files to Update:**
- `src/formatters/container.ts` (7 functions)
- `src/formatters/compose.ts` (2 functions)
- `src/formatters/host.ts` (3 functions)
- `src/formatters/scout.ts` (6 functions)
- `src/formatters/diagnostics.ts` (1 function)
### Phase 2: Structure Additions (High Priority)
**Effort:** Medium
**Impact:** High
1. Add legend lines to all mixed-state outputs
2. Add summary lines to all list operations
3. Standardize summary format with `|` separators
4. Add Request Echo lines for filtered outputs
**Affected Formatters:**
- `formatContainersMarkdown` - add legend + summary
- `formatComposeListMarkdown` - add legend + summary
- `formatComposeStatusMarkdown` - add legend
- `formatSearchResultsMarkdown` - add legend
- `formatImagesMarkdown` - add summary
- `formatNetworksMarkdown` - add summary
- `formatVolumesMarkdown` - add summary
### Phase 3: Metadata Enhancements (Medium Priority)
**Effort:** Medium
**Impact:** Medium
1. Add timestamp support to volatile data formatters
2. Implement trend symbol support for stats
3. Add automatic threshold warnings
**New Utilities Needed:**
- `formatTimestamp(): string` - returns `HH:MM:SS | MM/DD/YYYY` in EST
- `calculateTrend(current, previous): "↗"|"↘"|"→"` - trend detection
- `checkThresholds(metrics): Warning[]` - auto-warning generation
**Affected Formatters:**
- `formatStatsMarkdown` - add timestamp + trends
- `formatMultiStatsMarkdown` - add timestamp + trends
- `formatLogsMarkdown` - add timestamp
- `formatHostResourcesMarkdown` - add timestamp + trends + warnings
### Phase 4: Formatting Refinements (Low Priority)
**Effort:** Medium
**Impact:** Low
1. Implement `+N` overflow notation for ports/services
2. Implement `…` truncation character
3. Add severity-first sorting
4. Update pagination footer format
**Files to Update:**
- `src/formatters/utils.ts` - update `truncateIfNeeded`
- `src/formatters/container.ts` - overflow + sorting
- `src/formatters/compose.ts` - overflow + sorting
### Phase 5: Missing Features (Low Priority)
**Effort:** High
**Impact:** Low
1. Implement preview-first format for logs
2. Add boxed summaries for dense outputs
3. Add section dividers for long outputs
---
## Test Coverage Gaps
Current formatters have test files:
- `src/formatters/formatters.test.ts` (general tests)
- `src/formatters/strategy.test.ts` (strategy pattern tests)
**Missing Test Coverage:**
- Legend line rendering
- Summary line formatting
- Timestamp inclusion
- Trend symbol calculation
- Warning threshold detection
- Severity sorting
- Overflow notation
- Truncation patterns
**Recommended Test Structure:**
```typescript
describe("STYLE.md Compliance", () => {
describe("Symbol Usage", () => {
it("should use ● for running state");
it("should use ◐ for partial state");
it("should use ○ for stopped state");
// ... etc
});
describe("Structure", () => {
it("should include legend for mixed states");
it("should include summary line");
it("should include timestamp for volatile data");
// ... etc
});
describe("Formatting", () => {
it("should use +N for overflow counts");
it("should use … for truncation");
it("should sort by severity first");
// ... etc
});
});
```
---
## Dependencies and Impact Analysis
### Formatter Dependencies
All formatters import from:
- `../types.js` - TypeScript interfaces
- `../services/docker/utils/formatters.js` - `formatBytes` utility
- `./utils.js` - `truncateIfNeeded` utility
### Handler Dependencies
Handlers import from `../../formatters/index.js`:
- Container handlers: 7 container formatters
- Compose handlers: 2 compose formatters + inline formatters
- Docker handlers: 6 docker formatters
- Host handlers: 4 host formatters
- Scout handlers: 6 scout formatters
**Impact of Changes:**
- Symbol changes are low-risk (visual only, no logic changes)
- Structure additions are medium-risk (may break snapshot tests)
- Metadata additions are medium-risk (require data pipeline changes)
- Sorting changes are high-risk (may affect client expectations)
### Breaking Change Risk
**Low Risk:**
- Symbol replacements (visual changes only)
- Adding legend lines (additive)
- Adding summary lines (additive)
**Medium Risk:**
- Changing summary format (may affect parsing)
- Adding timestamps (changes output structure)
- Adding trends (requires data changes)
**High Risk:**
- Severity sorting (changes output order)
- Overflow notation (changes how counts are displayed)
- Preview-first log format (restructures logs)
---
## Conclusion
The formatter architecture is well-structured with clear domain separation, but STYLE.md compliance is low (32/100). The main gaps are:
1. **Symbol inconsistency** - Using emoji instead of canonical symbols
2. **Missing metadata** - No legends, summaries, timestamps, trends
3. **Incomplete formatting** - No overflow notation, wrong sorting
Remediation should follow the phased approach:
1. Symbol standardization (quick wins)
2. Structure additions (high value)
3. Metadata enhancements (medium value)
4. Formatting refinements (polish)
Estimated effort: 2-3 days for full compliance across all 27 formatters.
---
## Appendix: File Locations
### Formatters
- `src/formatters/index.ts`
- `src/formatters/strategy.ts`
- `src/formatters/utils.ts`
- `src/formatters/container.ts`
- `src/formatters/compose.ts`
- `src/formatters/docker.ts`
- `src/formatters/host.ts`
- `src/formatters/scout.ts`
- `src/formatters/diagnostics.ts`
### Handlers
- `src/tools/handlers/container.ts`
- `src/tools/handlers/compose.ts`
- `src/tools/handlers/compose-handlers.ts`
- `src/tools/handlers/docker.ts`
- `src/tools/handlers/host.ts`
- `src/tools/handlers/scout-simple.ts`
### Documentation
- `docs/STYLE.md` (source of truth)