Thanks for your interest in contributing to markdown-for-agents. This document covers the development workflow, coding standards, and how to submit changes.
# Clone the repository
git clone https://github.com/kkonstantinov/agent-markdown.git
cd agent-markdown
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm testThis is a monorepo managed with pnpm workspaces:
packages/
core/ # markdown-for-agents
src/
core/ # Parser, walker, renderer, converter, dedup
rules/ # Block, inline, list, table rules
extract/ # Content extraction (DOM pruning)
tokens/ # Token estimation
test/
unit/ # Vitest unit tests
integration/ # Runtime-specific integration tests (Node, Bun, Deno)
fixtures/ # HTML test fixtures
audit/ # @markdown-for-agents/audit
src/
index.ts # audit() function
cli.ts # CLI entry point
middleware/
express/ # @markdown-for-agents/express
fastify/ # @markdown-for-agents/fastify
hono/ # @markdown-for-agents/hono
nextjs/ # @markdown-for-agents/nextjs (+ nextImageRule)
web/ # @markdown-for-agents/web
examples/
nextjs/ # Next.js example app (route handler + proxy patterns)
docs/ # Documentation
See Architecture for how the pipeline works internally.
All scripts can be run from the root of the monorepo:
| Command | Description |
|---|---|
pnpm build |
Build all packages (tsdown) |
pnpm test |
Run all unit tests (vitest) |
pnpm test:watch |
Run tests in watch mode |
pnpm test:integration |
Build + run integration tests for all packages |
pnpm lint |
Run ESLint (includes Prettier checks) |
pnpm lint:fix |
Run ESLint with auto-fix (includes formatting) |
pnpm format |
Format all files with Prettier |
pnpm format:check |
Check formatting without writing |
pnpm typecheck |
Run TypeScript type checking for all packages |
You can also run scripts for a specific package:
pnpm --filter markdown-for-agents test
pnpm --filter @markdown-for-agents/express test| Command | Description |
|---|---|
pnpm --filter markdown-for-agents test:integration:node |
Run Node.js integration tests |
pnpm --filter markdown-for-agents test:integration:bun |
Run Bun integration tests |
pnpm --filter markdown-for-agents test:integration:deno |
Run Deno integration tests |
Unit tests use Vitest and live in each package's test/ directory. Run them with:
pnpm testCore tests are organized to mirror the source structure:
packages/core/test/unit/
converter.test.ts # End-to-end conversion tests
tokens.test.ts # Token estimation
extract.test.ts # Content extraction
core/
renderer.test.ts # Post-processing
walker.test.ts # DOM traversal and rule application
rules/
block.test.ts # Block-level element tests
inline.test.ts # Inline element tests
list.test.ts # List element tests
table.test.ts # Table element tests
integration/
fixtures.test.ts # Fixture-based integration tests
Each middleware package has its own unit and integration tests:
packages/middleware/express/test/
unit/express.test.ts # Unit tests with mocks
integration/express.test.ts # Real server integration tests
Integration tests verify the library works across runtimes (core) and with real servers (middleware). They test the built dist/ output:
# Run all integration tests (builds first)
pnpm test:integration
# Run core integration tests individually
pnpm --filter markdown-for-agents test:integration:node
pnpm --filter markdown-for-agents test:integration:bun
pnpm --filter markdown-for-agents test:integration:deno- Test behavior through the public
convert()API when possible - Use
toContainfor output assertions (avoids brittleness from whitespace changes) - Use
toBefor exact output when testing specific formatting - Add fixture files to
packages/core/test/fixtures/for complex HTML structures - When adding a new rule, add tests for: basic conversion, edge cases (empty content, nested elements), and options that affect the rule
HTML test fixtures live in packages/core/test/fixtures/:
simple.html/simple.md— basic conversion snapshottable.html— GFM table conversionnested-lists.html— nested list indentationcode-blocks.html— fenced code blocks with languagefull-page.html— full page with nav, header, footer, sidebar for extraction testing
The project uses ESLint v10 with:
typescript-eslint— strict type-checked ruleseslint-plugin-unicorn— recommended rules
pnpm lint # Check for errors
pnpm lint:fix # Auto-fix what's possible- Use
Number.parseInt()instead ofparseInt() - Use
.replaceAll()instead of.replace()with global regex - Use
isTag()type guards instead ofas anycasts - Use
path.resolve()with the default import (import path from "node:path")
- ESM only — all imports use
.jsextension (TypeScript convention for ESM) - No
as any— use proper type guards (isTag(),isText()from domhandler) - Null means remove — rule replacements return
nullto strip an element - Undefined means fall-through — rule replacements return
undefinedto try the next rule - Keep it simple — prefer straightforward code over abstractions. Three similar lines are better than a premature helper function.
- Add the rule to the appropriate file in
packages/core/src/rules/(block, inline, list, or table) - Add tests in the corresponding test file
- Update the "Supported Elements" table in
README.mdif adding a new element - Run
pnpm test && pnpm lintto verify
- Create a new package directory under
packages/middleware/ - Add
package.json,tsdown.config.ts,tsconfig.json,vitest.config.ts - Implement the middleware in
src/index.ts, importing frommarkdown-for-agents - Add unit tests in
test/unit/and integration tests intest/integration/ - Document it in
docs/middleware.md
If modifying the core pipeline (parser, walker, renderer):
- Read the Architecture doc first
- Ensure all existing tests still pass
- Consider edge cases: empty input, whitespace-only content, deeply nested structures, tables inside lists, pre-formatted content
- Fork the repository
- Create a feature branch from
main - Make your changes
- Run the full validation suite:
pnpm lint && pnpm typecheck && pnpm test && pnpm test:integration
- Open a pull request with a clear description of the change
- Keep PRs focused — one feature or fix per PR
- Include tests for new functionality
- Update documentation if the public API changes
- Ensure all CI checks pass
By contributing, you agree that your contributions will be licensed under the MIT License.