@electric_coding/wirefmt
v0.8.0
Published
Conservative ASCII wireframe formatter and linter with matching CLI and MCP surfaces.
Readme
wirefmt
wirefmt is a conservative ASCII wireframe formatter and linter with matching
CLI and MCP surfaces for the same small box workflows.
What It Does
- Normalizes single-box wireframe blocks that use
+,-, and|. - Normalizes exactly two or three adjacent sibling boxes in one block when they share the same row structure and each adjacent gap is one to three literal space columns.
- Normalizes one single-box compound panel layout when full-width interior divider rows separate stacked content panels.
- Preserves blank-line-separated non-box blocks around formatted boxes.
- Uses one shared core engine for the CLI and MCP tool.
- Leaves unsupported layouts unchanged instead of guessing.
- Keeps
formatandlintavailable through both CLI and MCP.
Runtime Model
- Installed package users need Node.js
>=18.17.0. - Contributors and release maintainers still use Bun
>=1.3.11.
Install
Published package for end users:
npm install -g @electric_coding/wirefmt
wirefmt --version
wirefmt-mcp --versionContributor setup from this checkout:
bun installRelease helper:
bun run release -- <patch|minor|major|x.y.z>Local tarball smoke-test flow:
bun run build
tarball="$(npm pack --json | node -e 'const fs = require("fs"); const input = fs.readFileSync(0, "utf8"); const match = input.match(/"filename"\\s*:\\s*"([^"]+\\.tgz)"/); if (!match) process.exit(1); console.log(match[1]);')"
tmp_dir="$(mktemp -d)"
npm install --prefix "$tmp_dir" "$PWD/$tarball"
"$tmp_dir/node_modules/.bin/wirefmt" --version
"$tmp_dir/node_modules/.bin/wirefmt-mcp" --versionInstalled executables:
wirefmtwirefmt-mcp
Run The CLI
You can run the CLI directly from this checkout:
bun run cli --helpBasic formatting from stdin:
printf '+--+\n|x|\n+--+\n' | bun run cli formatOutput:
+---+
| x |
+---+Formatting a file:
bun run cli format ./example.txtFormatting with an explicit outer width and padding:
printf '+---+\n|x|\n+---+\n' | bun run cli format --width 10 --pad 2Output:
+--------+
| x |
+--------+Formatting the supported adjacent sibling-box shape:
printf '+---+ +----+\n|a| |bb|\n+---+ +----+\n' | bun run cli format --width 10Output:
+--------+ +--------+
| a | | bb |
+--------+ +--------+Formatting the supported compound panel shape:
printf '+-----+\n|top|\n+-----+\n|mid |\n+-----+\n|bot|\n+-----+\n' | bun run cli format --width 10Output:
+--------+
| top |
+--------+
| mid |
+--------+
| bot |
+--------+CLI Reference
Usage:
wirefmt format [file] [--width <number>] [--pad <number>]
wirefmt lint [file] [--width <number>] [--pad <number>]
wirefmt --help
wirefmt --versionCommands:
format: Format a wireframe from a file or stdin.lint: Report lint findings for a file or stdin.
Flags:
--width: Target outer width, including borders.--pad: Inner spaces on both left and right sides of content. Default:1.--help: Show usage information.--version: Show the current version.
Exit codes:
0: Success.formatwrote formatted or unchanged text.lintfound no issues.formatwarnings are reported on stderr without changing the exit code.1:lintfound one or more issues.2: CLI usage or runtime error.
Notes:
- When
[file]is omitted, the CLI reads from stdin. formatwrites formatted or unchanged text to stdout and reports formatter warnings on stderr when a box-like block stays on the conservative pass-through path.formatalso supports exactly two or three adjacent sibling boxes in one block when adjacent boxes are separated by one to three literal space columns;widthandpadapply to each box independently, and supported layouts preserve the observed gap widths.formatalso supports one single-box compound panel layout with full-width divider rows;widthandpadapply to the whole box, and divider rows stay full width after normalization.lintcurrently accepts--widthand--padfor CLI surface parity, but the current lint engine does not use them when producing findings.
Lint Output
lint prints one line per issue:
<source>:<line-or-block>: <code> <message>Example:
printf '+--+\n|x\n+--+\n' | bun run cli lintOutput:
<stdin>:2: broken-border Content row is missing a closing edge.Current issue codes:
ambiguous-boxbroken-bordermisaligned-edgetext-outside-boxuneven-widthunsupported-adjacent-gapunsupported-adjacent-staggerunsupported-box-columnsunsupported-interior-borderunsupported-layout
MCP Usage
For direct checks from this checkout:
bun run mcp:help
bun run mcp:versionTo launch the stdio server for an MCP client from this checkout:
bun run mcp:serveAfter installation, an MCP client can also run:
wirefmt-mcpThe installed wirefmt-mcp wrapper launches the bundled dist/ server through
Node. For repo-local development, keep using:
bun run mcp:serveRegistered tools:
wirefmt.formatwirefmt.lint
MCP client wiring examples:
wirefmt.format input:
{
"text": "+--+\n|x|\n+--+\n",
"width": 10,
"pad": 1
}wirefmt.format result:
{
"formattedText": "+--------+\n| x |\n+--------+\n",
"changed": true
}wirefmt.lint input:
{
"text": "+--+\n|x\n+--+\n",
"source": "fixture.txt"
}wirefmt.lint result:
{
"issues": [
{
"code": "broken-border",
"message": "Content row is missing a closing edge.",
"source": "fixture.txt",
"lineOrBlock": "2"
}
]
}Notes:
warningsis omitted when the formatter has nothing to report.wirefmt.formatuses the same formatter as the CLI.wirefmt.lintuses the same lint engine and stable issue codes as the CLI.- MCP
structuredContentcarries the canonical result contract. Text content is still included for client compatibility.
Codex Setup
For an installed package, point Codex at the shipped executable:
[mcp_servers.wirefmt]
enabled = true
command = "wirefmt-mcp"For repo-local development, wire up the checkout directly with Bun. The shipped MCP tools are enough on their own; a custom skill is optional.
Add this to ~/.codex/config.toml:
[mcp_servers.wirefmt]
enabled = true
command = "bun"
args = ["run", "/Users/iamce/dev/electric/wirefmt/src/mcp/bin.ts"]Then restart Codex. If you want a persistent instruction, add something short like this to your relevant skill or agent instructions:
Use `wirefmt.format` to normalize supported ASCII wireframe boxes.
Use `wirefmt.lint` to inspect suspected problems without changing the input.
Do not fall back to the CLI unless the MCP server is unavailable.This repo also tracks a repo-local skill template at
skills/wirefmt/SKILL.md
with the matching agent prompt in
skills/wirefmt/agents/openai.yaml.
If you keep a separate shared skills repo, copy from those repo files so the
wirefmt instructions stay versioned with the tool.
Formatting Guarantees
widthis interpreted as the full outer width, including both borders.- If
widthis smaller than the minimum valid box width,wirefmtuses the minimum valid width instead of truncating content. - Content is trimmed, then rendered with the requested left and right padding.
- Blank-line-separated blocks stay separate.
- Leading blank lines, trailing blank lines, and the original line-ending style are preserved.
- Plain text that does not look like a box passes through unchanged.
- Unsupported or ambiguous box-like layouts pass through unchanged and may emit formatter warnings.
Non-Goals And Boundaries
wirefmt is intentionally conservative. It does not try to repair or reinterpret
every ASCII diagram.
Current non-goals:
- Formatting four or more adjacent boxes or broader column layouts in one block.
- Formatting two-box or three-box layouts with four-plus space gaps, staggered rows, or mismatched vertical structure.
- Formatting compound boxes with empty panels, partial-width divider rows, or nested interior structure.
- Moving or rewriting text that appears outside the detected box.
- Acting as a general-purpose ASCII art formatter.
- Inferring author intent when the border shape is ambiguous.
If a block falls outside the supported shape, format preserves the original
text and reports a warning when appropriate. Common conservative cases use
stable diagnostics instead of one generic unsupported warning:
unsupported-box-columns: four-plus sibling boxes or broader column layoutsunsupported-adjacent-gap: adjacent boxes separated by unsupported gapsunsupported-adjacent-stagger: adjacent boxes that do not share one row structureunsupported-interior-border: unsupported interior-divider structure inside one boxtext-outside-box: trailing or surrounding text outside the detected box
Use lint to surface likely problems without changing the input.
Releases
Normal PRs do not need release metadata.
When you want to cut a release, run:
bun run release -- <patch|minor|major|x.y.z>That command:
- bumps the package version
- updates
CHANGELOG.md - runs the release gate
- verifies the packaged tarball from a clean temp install
- commits and tags the release
- pushes the tag for publication
The GitHub Actions release workflow then publishes the tagged version and uses
the matching CHANGELOG.md entry for the GitHub release notes.
Use CHANGELOG.md for shipped history and docs/release.md for the maintainer runbook.
