@openverb/markdown
v0.1.0
Published
Reference implementation of the OpenVerb Markdown (OVM) specification — generate, validate, and sync human-readable verb manifests
Maintainers
Readme
@openverb/markdown
The reference implementation of the OpenVerb Markdown (OVM) specification.
OpenVerb Markdown turns raw verb schemas into a browsable, shareable, GitHub-friendly manifest that shows exactly what an application can do — readable by humans and agents alike.
OpenVerb (execution) → OpenVerb Markdown (human interface) → Email/GitHub (distribution)What is OVM?
OpenVerb Markdown (OVM) is a standardised manifest format for OpenVerb systems. It bridges the gap between machine-readable JSON schemas and human understanding.
Before OVM — developers see this:
{ "name": "send_email", "params": { "to": { "type": "array" } } }After OVM — everyone sees this:
## send_email
**Purpose:** Send an email to one or more recipients.
**Category:** Communication
**Risk Level:** Medium
**Requires Auth:** Yes
### Inputs
| Field | Type | Required | Description |
| ------ | ------ | ------ | ------------ |
| `to` | array | Yes | Recipient email addresses |Installation
npm install -g @openverb/markdown
# or use without installing:
npx @openverb/markdown generateAs a project dependency:
npm install --save-dev @openverb/markdownQuick Start
# 1. Initialise a new project
openverb-md init
# 2. Edit verbs/schema.json with your verb definitions
# 3. Generate the manifest
openverb-md generate
# 4. Validate the output
openverb-md validate openverb.mdCLI Reference
generate
Generate an openverb.md manifest from a verb library.
openverb-md generate [options]
Options:
-i, --input <path> Path to verb library JSON or directory (default: ./verbs)
-o, --output <path> Output path for openverb.md (default: ./openverb.md)
--split-verbs Also generate /verbs/*.md per-verb files
--verbs-dir <path> Directory for per-verb files (default: ./verbs-md)
--force Overwrite existing file entirelySmart sync behaviour: If openverb.md already exists and contains <!-- ov:auto --> markers, generate automatically syncs only the auto-generated sections, preserving your human-authored content.
# First run — creates openverb.md
openverb-md generate
# Subsequent runs — syncs auto sections, preserves human edits
openverb-md generate
# Force full regeneration
openverb-md generate --force
# Also create per-verb files
openverb-md generate --split-verbsvalidate
Validate an existing openverb.md against the OVM specification.
openverb-md validate [file]
Arguments:
file Path to openverb.md (default: ./openverb.md)Checks for:
- Required document sections (Overview, Verb Index, Verb Definitions)
- Required verb fields (Purpose, Category, Risk Level, Requires Auth, Billable, Inputs, Returns, Policy Notes, Example)
- Valid Risk Level values (Low, Medium, High)
- Valid Billable values (Yes, No, Optional)
- Valid JSON in Example blocks
- Verb Index / Definitions alignment
openverb-md validate # validates ./openverb.md
openverb-md validate docs/verbs.md # validates a specific fileExit code 0 = valid, 1 = invalid (CI-safe).
sync
Update auto-generated sections while preserving human-authored content.
openverb-md sync [file] [options]
Arguments:
file Path to openverb.md (default: ./openverb.md)
Options:
-i, --input <path> Path to verb library (default: ./verbs)Everything inside <!-- ov:auto:start --> / <!-- ov:auto:end --> markers is regenerated. Everything outside is left untouched.
openverb-md sync
openverb-md sync ./docs/openverb.md --input ./src/verbsinit
Initialise a new OVM project with a starter config and example verb library.
openverb-md init [dir]
Arguments:
dir Directory to initialise in (default: .)Creates:
openverb.config.json— project configverbs/schema.json— example verb library with 3 verbs
Config File
Create openverb.config.json in your project root:
{
"input": "./verbs",
"output": "./openverb.md",
"splitVerbs": true,
"verbsDir": "./verbs-md"
}CLI flags always override config file values.
Verb Library Format
OVM reads verb libraries via the openverb package. Your JSON follows the OpenVerb schema, with an optional ovm field per verb for OVM-specific metadata:
{
"namespace": "my_app",
"version": "1.0.0",
"description": "My application capabilities",
"verbs": [
{
"name": "send_email",
"category": "Communication",
"description": "Send an email to one or more recipients.",
"params": {
"to": { "type": "array", "description": "Recipients", "required": true },
"subject": { "type": "string", "description": "Subject line", "required": true },
"body": { "type": "string", "description": "Email content", "required": true }
},
"returns": {
"messageId": { "type": "string", "description": "Message ID" },
"status": { "type": "string", "description": "Delivery status" }
},
"ovm": {
"riskLevel": "Medium",
"requiresAuth": true,
"billable": "Optional",
"policyNotes": ["Rate limited to 100/day", "Requires send_email entitlement"],
"sideEffects": ["Sends external email"],
"tags": ["email", "communication"],
"example": {
"to": ["[email protected]"],
"subject": "Update",
"body": "Your report is ready."
}
}
}
],
"ovmMeta": {
"workflows": [
{ "name": "Lead Onboarding", "steps": ["create_contact", "send_email"] }
]
}
}OVM Verb Metadata (ovm field)
| Field | Type | Values | Description |
| ------ | ------ | ------ | ------------ |
| riskLevel | string | Low, Medium, High | Risk level (inferred from destructive/requires_confirmation if omitted) |
| requiresAuth | boolean | — | Whether authentication is required (default: true) |
| billable | string | Yes, No, Optional | Whether usage incurs a charge |
| policyNotes | string[] | — | Policy constraints shown in Policy Notes section |
| sideEffects | string[] | — | External effects of calling this verb |
| tags | string[] | — | Searchable tags |
| example | object | — | Example input JSON (auto-generated from required params if omitted) |
Human-Authored Sections
OVM uses marker comments to separate generated from human content:
### my_verb
<!-- ov:auto:start -->
**Purpose:** Auto-generated content here.
...tables, examples, policy notes...
<!-- ov:auto:end -->
### Human Notes
This section is **outside** the markers — it will never be overwritten by sync.
You can add context, usage tips, links to related verbs, or anything else.Running sync or generate again will update the content inside the markers while leaving everything outside untouched.
Programmatic API
import {
generateMarkdown,
validateMarkdown,
syncMarkdown,
initProject,
} from '@openverb/markdown';
// Generate
await generateMarkdown({
input: './verbs',
output: './openverb.md',
splitVerbs: true,
});
// Validate
const result = await validateMarkdown({ filePath: './openverb.md' });
if (!result.valid) {
console.error(result.errors);
}
// result.warnings for non-fatal issues
// Sync (preserves human edits)
await syncMarkdown({
filePath: './openverb.md',
input: './verbs',
});
// Init a new project
await initProject({ dir: '.' });Generated File Structure
# OpenVerb Manifest
**Version:** 1.0.0
**Namespace:** crm
**Generated From:** ./verbs
**Last Updated:** 2026-05-03
---
## Overview
CRM capabilities including contact management...
---
## Verb Index
| Verb | Category | Description |
| ... |
---
## Verb Definitions
### create_contact
<!-- ov:auto:start -->
**Purpose:** Create a new contact record.
**Category:** CRM
**Risk Level:** Low
...
<!-- ov:auto:end -->
---
## Policy Summary
| Verb | Tier | Rate Limit |
| ... |
---
## Workflows
### Lead Onboarding
1. `create_contact`
2. `send_email`Multi-File Mode
With --split-verbs, OVM generates a file per verb alongside the main manifest:
/openverb.md ← root manifest (Verb Index + all definitions)
/verbs-md/
create_contact.md ← standalone verb page
send_email.md
export_report.mdThis renders cleanly in GitHub repos, docs portals, and static site generators.
GitHub Action
Add this to your repo to auto-regenerate openverb.md when verb schemas change:
# .github/workflows/generate-ovm.yml
name: OpenVerb Markdown
on:
push:
paths: ['verbs/**', 'openverb.config.json']
jobs:
generate:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm install -g @openverb/markdown
- run: openverb-md generate
- run: openverb-md validate openverb.md
- run: |
git config user.name "OVM Bot"
git config user.email "[email protected]"
git add openverb.md
git diff --staged --quiet || git commit -m "chore: regenerate openverb.md [skip ci]" && git pushA full workflow file is included at .github/workflows/generate-ovm.yml.
OVM Specification (v0.1)
This package implements OVM v0.1. Key rules:
| Rule | Detail |
| ------ | ------ |
| §5.1 Header | Must start with # OpenVerb Manifest |
| §5.2 Metadata | Must include Version, Generated From, Last Updated |
| §5.4 Verb Index | Table of all verbs with name, category, description |
| §6 Verb Format | Each verb: Purpose, Category, Risk Level, Requires Auth, Billable, Inputs, Returns, Policy Notes, Example |
| §7.1 Markdown | GitHub-compatible standard Markdown |
| §7.3 Tables | Inputs: Field\|Type\|Required\|Description / Returns: Field\|Type\|Description |
| §7.4 Types | string, number, boolean, object, array |
| §7.5 Required | Explicitly Yes or No |
| §7.6 Examples | Must be valid JSON |
Architecture
src/
index.ts ← Public library API
types.ts ← All TypeScript types
cli/
index.ts ← Commander CLI (generate, validate, sync, init)
core/
loader.ts ← Verb library loading (via openverb package)
markers.ts ← ov:auto marker utilities
syncEngine.ts ← Sync logic (preserve human edits)
generators/
manifestGenerator.ts ← Full openverb.md assembly
verbFormatter.ts ← Per-verb Markdown formatting
parsers/
ovmParser.ts ← Parse existing openverb.md
validators/
ovmValidator.ts ← Validate against OVM specKey design principle: This package delegates all verb parsing and schema understanding to the openverb package. It never reimplements OpenVerb core logic.
Examples
See the examples/crm-app/ directory for a complete CRM application with 6 verbs across 4 categories.
cd examples/crm-app
node ../../dist/cli/index.js generate
node ../../dist/cli/index.js validate openverb.mdLicense
MIT
