Skip to content

Commit 63d4953

Browse files
authored
feat: add markitdown ingest skill and optional MCP
feat: add markitdown ingest skill and optional MCP Markdown converter only. SmartDoc keeps contract/QA/render. Catalog 64 = 48 model + 16 manual. VERSION stays 1.8.2.
1 parent faaa812 commit 63d4953

26 files changed

Lines changed: 289 additions & 20 deletions

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
## Unreleased
44

5-
Catalog update for AI LABS 8-repo wave adaptation and hygiene patch. Totals become **63** (47 model-invoked, 16 manual slash commands).
5+
Catalog update for AI LABS 8-repo wave adaptation, hygiene patch, and MarkItDown ingest. Totals become **64** (48 model-invoked, 16 manual slash commands).
66

7+
- Add model-invoked specialist `markitdown` as a Markdown ingest converter (Office/PDF/HTML/CSV/XLSX/PPTX/EPUB/ZIP). Optional MCP `opencode-bf markitdown enable` registers local stdio (`uvx --from markitdown-mcp markitdown-mcp`). `FOREIGN_ON_DEMAND`. SmartDoc keeps contract/QA/render. No npm plugin, no Azure keys, no docker bind-all.
78
- Add first-party model-invoked specialist `img2threejs` for code-only procedural Three.js TypeScript model reconstruction from reference object images (editable Group factory, visible vs. inferred geometry spec, screenshot loop gate; no mesh blob downloads).
89
- Add optional `reticle` MCP (`opencode-bf reticle enable` / `disable`) registering local perception server (`npx -y @reticlehq/server mcp`). `FOREIGN_ON_DEMAND`, server is FSL-1.1-ALv2, perception only, never an auto-implementer; default verification remains `playwright-qa` / `chrome-devtools-axi`.
910
- Add optional `ui-skills` remote MCP (`opencode-bf ui-skills enable` / `disable`) registering `https://www.ui-skills.com/mcp` for design-skill lookup only. Product UI remains Design Bank + Impeccable + Design V2 atoms + shadcn; `BANK_MISS` never generates from random ui-skills documents.

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# OpenCodeBestFriend
22

33
Production-ready capability layer for OpenCode:
4-
63 routed skills (core + Wave 2/3 warehouse specialists), MCP, Codebase Memory,
4+
64 routed skills (core + Wave 2/3 warehouse specialists), MCP, Codebase Memory,
55
Design Bank, Design Intelligence, SmartDoc, browser and verification tooling.
66

77
OpenCodeBestFriend is an installer and runtime overlay for [OpenCode](https://opencode.ai). It is **not** Claude Code, **not** a model provider, and **not** a dump of a developer home directory.
88

99
## What it is
1010

11-
- 63 skills: 47 model-invoked, 16 manual slash commands
11+
- 64 skills: 48 model-invoked, 16 manual slash commands
1212
- A thin `AGENTS.md` router (lazy, one primary specialist)
1313
- Core MCP: Codebase Memory, Context7, shadcn
1414
- Design Bank discovery or download (media is **not** in git)
@@ -61,7 +61,7 @@ Restart OpenCode after install. Config is not hot-reloaded.
6161
┌───────────────────┼────────────────────┐
6262
▼ ▼ ▼
6363
Skills MCP Rules
64-
47 automatic Codebase Memory Verification
64+
48 automatic Codebase Memory Verification
6565
16 manual Context7 Engineering
6666
shadcn
6767
@@ -100,6 +100,7 @@ Default: repository evidence first. Then at most one specialist.
100100
| Procedural Three.js object from image | `img2threejs` |
101101
| Deterministic HTML composition video | `hyperframes` |
102102
| Documents (PDF/DOCX/answer/extract/review) | `smartdoc` |
103+
| File to Markdown ingest | `markitdown` |
103104
| Reusable book/module knowledge | `smartbook-ingest` |
104105
| Scholarly literature & manuscripts | `academic` |
105106
| Prose AI-tell removal & humanizing | `humanizer` (`/unslop`) |
@@ -129,6 +130,7 @@ Optional:
129130
- `stitch``opencode-bf stitch enable` registers Google Stitch as a remote comp/mock source. Not an owned core server and not a production UI implementer: hand screens to `found-this-design` or `impeccable` before shipping. Keys are never written into config, only referenced as `{env:STITCH_API_KEY}`, or omitted with `--oauth`. `opencode-bf stitch disable` removes only that server key. Absent is not a `doctor` failure; a malformed entry fails closed.
130131
- `reticle``opencode-bf reticle enable` registers Reticle as a local perception server (`npx -y @reticlehq/server mcp`). `FOREIGN_ON_DEMAND`. Server package is FSL-1.1-ALv2 (competing-use clause); SDK packages (Apache-2.0) are not vendored. Never an auto-implementer; default verification remains `playwright-qa` / `chrome-devtools-axi`. `opencode-bf reticle disable` removes only that server key. Absent is not a `doctor` failure; a malformed entry fails closed.
131132
- `ui-skills``opencode-bf ui-skills enable` registers UI Skills (`https://www.ui-skills.com/mcp`) as an optional remote MCP server. `FOREIGN_ON_DEMAND` for design-skill lookup only. Product UI remains Design Bank + Impeccable + Design V2 atoms + shadcn; `BANK_MISS` never generates from a random ui-skills document. `opencode-bf ui-skills disable` removes only that server key. Absent is not a `doctor` failure; a malformed entry fails closed.
133+
- `markitdown``opencode-bf markitdown enable` registers MarkItDown as a local stdio ingest converter (`uvx --from markitdown-mcp markitdown-mcp`). `FOREIGN_ON_DEMAND`. Local trusted agents only; never `--http` / `0.0.0.0` / docker bind-all. Output is Markdown data; SmartDoc keeps contract/QA/render. `opencode-bf markitdown disable` removes only that server key. Absent is not a `doctor` failure; a malformed entry fails closed.
132134
- `exa``FOREIGN_ON_DEMAND`; installer never adds, removes, or overwrites it
133135

134136
NVIDIA SkillEvaluator is `FOREIGN_ON_DEMAND` in the same sense: a maintainer may run it externally for embedding-based overlap scoring or live catalog evaluation. Caliper is `FOREIGN_ON_DEMAND` similarly: a maintainer may `pipx install caliper-eval` off-tree for prompt/agent benchmark evaluation. Neither is vendored into `lib/`, the installer never adds them, `doctor` does not fail when they are absent, and a malformed MCP entry fails closed like any other schema violation.

docs/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
┌───────────────────┼────────────────────┐
1111
▼ ▼ ▼
1212
Skills MCP Rules
13-
47 automatic Codebase Memory Verification
13+
48 automatic Codebase Memory Verification
1414
16 manual Context7 Engineering
1515
shadcn
1616

docs/mcp.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Optional:
1616
- `stitch``opencode-bf stitch enable` (remote comp/mock source only; auth via `{env:STITCH_API_KEY}` or `--oauth`)
1717
- `reticle``opencode-bf reticle enable` (local stdio via `npx -y @reticlehq/server mcp`; perception only, never auto-implementer)
1818
- `ui-skills``opencode-bf ui-skills enable` (remote HTTP `https://www.ui-skills.com/mcp`; design-skill lookup only)
19+
- `markitdown``opencode-bf markitdown enable` (local stdio via `uvx --from markitdown-mcp markitdown-mcp`; Markdown ingest only)
1920
- `exa` — foreign; never add/remove/overwrite
2021

2122
Merge is parse-aware. Comment-free JSON is rewritten with `json.dumps`. JSONC with comments is patched surgically (owned MCP keys only). If surgical merge cannot be verified, install fails closed instead of destroying comments.
@@ -29,3 +30,5 @@ Doctor reports `CONFIGURED` for owned MCP entries present in config. That is not
2930
`opencode-bf reticle enable` configures Reticle as an optional local perception MCP server (`npx -y @reticlehq/server mcp`). It is `FOREIGN_ON_DEMAND`. The server package is FSL-1.1-ALv2 (competing-use clause); SDK packages (Apache-2.0) are not vendored. Reticle is never an auto-implementer; after a feature is done, default verification remains `playwright-qa` or `chrome-devtools-axi`. Reticle is extra perception if the user enabled it. `opencode-bf reticle disable` surgically removes only the reticle server key. Absent is not a doctor failure; a malformed entry fails closed.
3031

3132
`opencode-bf ui-skills enable` configures UI Skills as an optional remote MCP server (`https://www.ui-skills.com/mcp`). It is `FOREIGN_ON_DEMAND` for design-skill lookup only (`list_skills`, `get_skill`). Product UI remains Design Bank + Impeccable + Design V2 atoms + shadcn; `BANK_MISS` never generates from a random ui-skills document. `opencode-bf ui-skills disable` surgically removes only the ui-skills server key. Absent is not a doctor failure; a malformed entry fails closed.
33+
34+
`opencode-bf markitdown enable` configures MarkItDown as an optional local stdio ingest MCP (`uvx --from markitdown-mcp markitdown-mcp`). It is `FOREIGN_ON_DEMAND`. Official server is for local trusted agents only; never `--http`, never bind `0.0.0.0`, never docker bind-all. The converter is not vendored into `lib/`. Missing `uvx` is documented in the skill (CLI/`pipx`/`enable`); enable still writes the stdio command like reticle. `opencode-bf markitdown disable` surgically removes only the markitdown server key. Absent is not a doctor failure; a malformed entry (including `--http` / `0.0.0.0`) fails closed.

docs/routing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ UI direction from the bank routes to `found-this-design` first, which stops befo
2626

2727
Browser verification follows four explicit doors: exploratory application UI routes to `playwright-qa`, persistent multi-account sessions route to `browser-act`, observed Chromium cause routes to `chrome-devtools-axi`, and button handler sequential undo / shared-store side effects route to `click-path-audit`.
2828

29-
Documents (answer, create, transform, extract, review, PDF/DOCX) route to `smartdoc`. Reusable book/module knowledge routes to `smartbook-ingest`. `/docx` and `/pdf` are missing aliases; nearest is `smartdoc`. `/pptx` is NOT_APPLICABLE. Do not add `commands/pdf.md` or `commands/docx.md`. Impeccable `document` remains DESIGN.md generation.
29+
Documents (answer, create, transform, extract, review, PDF/DOCX) route to `smartdoc`. File-to-Markdown ingest routes to `markitdown`. Reusable book/module knowledge routes to `smartbook-ingest`. `/docx` and `/pdf` are missing aliases; nearest is `smartdoc`. `/pptx` is NOT_APPLICABLE. Do not add `commands/pdf.md` or `commands/docx.md`. Impeccable `document` remains DESIGN.md generation.
3030

3131
Prose AI-tell removal and natural tone polishing route to `humanizer` (`/unslop` is its manual alias). Scholarly research, academic manuscripts, and structured peer critique route to `academic`. Deterministic HTML composition rendered to video routes to `hyperframes`. Editorial technical diagrams (HTML/SVG) route to `diagram-design`.
3232

docs/skills.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
Policy: `vendor/skill-policy.json` plus `vendor/skill-allowlist.txt`.
44

5-
- 47 model-invoked skills live under `skills/` and install to `~/.config/opencode/skills/` (core + Wave 2/3 warehouse specialists)
5+
- 48 model-invoked skills live under `skills/` and install to `~/.config/opencode/skills/` (core + Wave 2/3 warehouse specialists)
66
- 16 manual skills live under `manual-skills/` and install to `~/.config/opencode/bestfriend/skills/` plus `commands/`
77

8-
`smartdoc` is per-job document intelligence. `smartbook-ingest` compiles reusable local knowledge. `humanizer` cleans user-facing prose tells (`/unslop` is its manual alias). `academic` manages scholarly research, writing, and peer review. `hyperframes` handles deterministic HTML-to-MP4 video composition. `diagram-design` crafts editorial HTML/SVG diagrams. `img2threejs` reconstructs procedural Three.js models from reference images. Warehouse diagnostics include `agent-architecture-audit` (agent stack layers), `cost-aware-llm-pipeline` (token budgeting), `eval-harness` (benchmarks), `prompt-optimizer` (prompt refinement), and `skill-stocktake` (catalog hygiene). Wave 3 adds `api-design`, `contract-first`, `automation-audit-ops`, `code-tour`, and `click-path-audit`. Handwriting is a SmartDoc renderer, not a skill.
8+
`smartdoc` is per-job document intelligence. `markitdown` converts Office/PDF/HTML/CSV/XLSX/PPTX/EPUB/ZIP to Markdown for ingest; SmartDoc keeps contract/QA/render. `smartbook-ingest` compiles reusable local knowledge. `humanizer` cleans user-facing prose tells (`/unslop` is its manual alias). `academic` manages scholarly research, writing, and peer review. `hyperframes` handles deterministic HTML-to-MP4 video composition. `diagram-design` crafts editorial HTML/SVG diagrams. `img2threejs` reconstructs procedural Three.js models from reference images. Warehouse diagnostics include `agent-architecture-audit` (agent stack layers), `cost-aware-llm-pipeline` (token budgeting), `eval-harness` (benchmarks), `prompt-optimizer` (prompt refinement), and `skill-stocktake` (catalog hygiene). Wave 3 adds `api-design`, `contract-first`, `automation-audit-ops`, `code-tour`, and `click-path-audit`. Handwriting is a SmartDoc renderer, not a skill.
99

1010
OpenCode 1.18.x has no `disable-model-invocation` field. Manual skills must not be copied into the discovered skills directory.
1111

docs/warehouse-inventory.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,19 @@ Evaluation and disposition contract for the AI LABS 8-repo wave (procedural 3D,
367367
| `swiftui-skills` | **DEFER** | `-` | Apple platform / Xcode 26 ecosystem deferred. Target platform gate remains Linux x86_64 and OpenCode 1.18.x. |
368368
| `caliper` | **FOREIGN_ON_DEMAND** | `-` | Benchmark CLI runner (`caliper-eval`). Maintainer may run off-tree via pipx; zero `lib/` vendor coupling. |
369369
| `anti-slop` | **MERGE** | `install-anti-slop`, `impeccable`, `rules/03-prose-discipline.md` | Anti-pattern guardrails merged into existing taste, prose, and linting references; zero extra catalog skills. |
370+
371+
---
372+
373+
## Wave MarkItDown
374+
375+
Microsoft MarkItDown as an ingest converter, not a second document OS. SmartDoc keeps contract/QA/render.
376+
377+
| Candidate / Repo | Decision | BestFriend Target | Reason |
378+
| :--- | :---: | :--- | :--- |
379+
| `microsoft/markitdown` CLI/lib | **NEW** | `skills/markitdown` | Thin first-party skill: convert Office/PDF/HTML/CSV/XLSX/PPTX/EPUB/ZIP to Markdown, then hand off. |
380+
| `markitdown-mcp` official | **FOREIGN_ON_DEMAND** | `mcp.markitdown` | Optional local stdio (`uvx --from markitdown-mcp markitdown-mcp`). Local trusted agents only. |
381+
| `opencode-markitdown` npm plugin | **REJECT** | `-` | Config-hook mutation forbidden. |
382+
| community `trsdn-markitdown-mcp` | **REJECT** | `-` | Not Microsoft. |
383+
| Azure Document Intelligence / Content Understanding | **DEFER** | `-` | No keys in config. |
384+
| youtube / audio extras | **DEFER** | `-` | Out of document lane. |
385+
| Duplicate SmartDoc modes | **REJECT** | `-` | SmartDoc keeps contract/QA/render. |

lib/cli.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
cmd_install,
2525
cmd_restore,
2626
cmd_restore_list,
27+
cmd_markitdown_disable,
28+
cmd_markitdown_enable,
2729
cmd_reticle_disable,
2830
cmd_reticle_enable,
2931
cmd_serena_enable,
@@ -111,6 +113,9 @@ def build_parser() -> argparse.ArgumentParser:
111113
ret = sub.add_parser("reticle", help="optional Reticle local perception MCP")
112114
ret.add_argument("action", choices=["enable", "disable"])
113115

116+
md = sub.add_parser("markitdown", help="optional MarkItDown local ingest MCP")
117+
md.add_argument("action", choices=["enable", "disable"])
118+
114119
uis = sub.add_parser("ui-skills", help="optional UI Skills remote MCP")
115120
uis.add_argument("action", choices=["enable", "disable"])
116121

@@ -177,6 +182,10 @@ def main(argv: list[str] | None = None) -> int:
177182
if args.action == "enable":
178183
return cmd_reticle_enable()
179184
return cmd_reticle_disable()
185+
if cmd == "markitdown":
186+
if args.action == "enable":
187+
return cmd_markitdown_enable()
188+
return cmd_markitdown_disable()
180189
if cmd == "ui-skills":
181190
if args.action == "enable":
182191
return cmd_ui_skills_enable()

lib/doctor.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ def mcp_status_map() -> dict[str, str]:
118118
try:
119119
data = jsonc.load_path(cfg)
120120
except (OSError, json.JSONDecodeError, ValueError):
121-
return {k: "FAIL" for k in ("codebase-memory-mcp", "context7", "shadcn", "serena", "stitch", "reticle", "ui-skills", "exa")}
121+
return {k: "FAIL" for k in ("codebase-memory-mcp", "context7", "shadcn", "serena", "stitch", "reticle", "ui-skills", "markitdown", "exa")}
122122
mcp = data.get("mcp") or {}
123123
owned = {"codebase-memory-mcp", "context7", "shadcn"}
124-
optional = {"serena", "stitch", "reticle", "ui-skills", "exa"}
125-
for name in ("codebase-memory-mcp", "context7", "shadcn", "serena", "stitch", "reticle", "ui-skills", "exa"):
124+
optional = {"serena", "stitch", "reticle", "ui-skills", "markitdown", "exa"}
125+
for name in ("codebase-memory-mcp", "context7", "shadcn", "serena", "stitch", "reticle", "ui-skills", "markitdown", "exa"):
126126
spec = mcp.get(name)
127127
if spec is None:
128128
out[name] = "OPTIONAL_ABSENT" if name in optional else "FAIL"
@@ -165,6 +165,21 @@ def mcp_status_map() -> dict[str, str]:
165165
continue
166166
out[name] = "CONFIGURED"
167167
continue
168+
if name == "markitdown":
169+
typ = spec.get("type")
170+
cmd = spec.get("command")
171+
if typ != "local" or not isinstance(cmd, list) or not cmd:
172+
out[name] = "FAIL"
173+
continue
174+
joined = " ".join(str(part) for part in cmd)
175+
if "--http" in joined or "0.0.0.0" in joined:
176+
out[name] = "FAIL"
177+
continue
178+
if cmd[0] != "uvx" or "markitdown-mcp" not in cmd:
179+
out[name] = "FAIL"
180+
continue
181+
out[name] = "CONFIGURED"
182+
continue
168183
if name not in owned:
169184
out[name] = "FOREIGN"
170185
continue

lib/install.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ def take(src: Path, dest: Path) -> None:
872872
"modelInvokedSkills": meta["model"],
873873
"manualSkills": meta["manual"],
874874
"ownedMcp": list(OWNED_MCP),
875-
"optionalMcp": ["serena", "stitch", "reticle", "ui-skills", "exa"],
875+
"optionalMcp": ["serena", "stitch", "reticle", "ui-skills", "markitdown", "exa"],
876876
"designBank": {
877877
"root": bank_root,
878878
"source": bank_source,
@@ -1402,6 +1402,19 @@ def cmd_reticle_disable() -> int:
14021402
return _optional_mcp_disable("reticle")
14031403

14041404

1405+
def cmd_markitdown_enable() -> int:
1406+
spec: dict[str, object] = {
1407+
"type": "local",
1408+
"command": ["uvx", "--from", "markitdown-mcp", "markitdown-mcp"],
1409+
"enabled": True,
1410+
}
1411+
return _optional_mcp_enable("markitdown", spec)
1412+
1413+
1414+
def cmd_markitdown_disable() -> int:
1415+
return _optional_mcp_disable("markitdown")
1416+
1417+
14051418
def cmd_ui_skills_enable() -> int:
14061419
spec: dict[str, object] = {
14071420
"type": "remote",

0 commit comments

Comments
 (0)