# Korean official documents — hwp and hwpx

> **What this chapter covers**
> Reading `.hwp` / `.hwpx` as material, generating official documents from
> Markdown, and **filling blank forms automatically**.

## The extension the previous chapter didn't have

[Turning documents into material](/guide/ht-documents) covered four formats —
`pdf` · `docx` · `xlsx` · `pptx`. **The extension you meet most often in Korean
practice is not on that list.**

Government notices, grant applications, internal drafts, meeting-minute
templates — they arrive as `.hwp` or `.hwpx`. And most automation stops right
there, because the received wisdom is that **you need a Windows PC with Hancom
Office installed.**

You don't.

## First — the two extensions are different formats

**This is where things go wrong most often.**

| | `.hwp` | `.hwpx` |
|---|---|---|
| What it is | Binary (HWP 5.x) | ZIP + XML |
| Reading | Works | Works |
| **Writing / editing** | **Doesn't** | Works |

Both can be read, but **only `.hwpx` can be created or modified.** Everything
generated, filled or patched below comes out as `.hwpx`. If someone needs
`.hwp`, a person re-saves it from Hangul at the end.

## The tool — kordoc

One npm package, invoked **without installing it**.

```bash
npx -y kordoc@^4 <command> ...
```

- **Node.js 18+ is the only requirement.** No Hancom Office, no Windows, no COM
  automation. It runs on a macOS or Linux server as-is.
- Only the first call is slow while the package downloads; after that it's
  cached.
- `@^4` pins the major version. That is the opposite of the advice for
  [yt-dlp in the previous chapter](/guide/ht-video-collect) — here the other
  side is a **document format spec**, not a platform, and it doesn't shift
  weekly.

## 1. Reading — anything into Markdown

```bash
npx -y kordoc@^4 business-plan.hwp -o business-plan.md
```

The **text copy** idea from [Turning documents into
material](/guide/ht-documents) holds here too. Put the Markdown next to the
original and search starts working.

| What you want | What to add |
|---|---|
| A whole folder | `-d ./converted/` |
| Specific pages | `-p 1-3` or `-p 1,3,5` |
| Structured JSON | `--format json` |

The same command also reads **PDF, DOCX and XLS/XLSX** — useful when a bundle
from an agency arrives with mixed extensions.

> **Tables come out as HTML `<table>`, not GFM.** Merged and nested cells in
> official documents can't be expressed as pipe tables. That means the merges
> survived — use them as they are. Equations come out as LaTeX (`$...$`).

### Spotting a scan

For PDFs, a text-layer quality signal is computed alongside the extraction. **A
`needsOcr` signal means it's a scan** — pictures of letters, not letters.
kordoc has no built-in OCR, so that's where you stop and find another route. A
PDF whose tables look shredded is usually this case.

## 2. Generating — from Markdown to an official document

```bash
npx -y kordoc@^4 draft.md -o report.hwpx --preset 보고서
```

There are seven presets — `기안문` (official draft) · `보고서` (report) ·
`계획서` (plan) · `통지` (notice) · `회의록` (minutes) · `개조식` (outline
style, with cover and contents) · `보도자료` (press release).

**What this automates is most of the actual tedium of official documents.**

| What you write in Markdown | What comes out |
|---|---|
| `1.` / indented `-` | The 8-level official numbering (1. → 가. → 1) → 가) → …) |
| — | Hamchorom Batang, official margins, standard formatting |
| GFM pipe tables | Tables |
| `$$...$$` | Native Hangul equations |
| A ` ```chart ` fence | Native Hangul charts (column, line, pie, doughnut, …) |

Getting the numbering levels and hanging indents right by hand is slow and
frequently wrong. **Write the content in Markdown and hand off the formatting**
— that's the point of this command.

Body options: `--font gothic` · `--pt <size>` · `--line-spacing <percent>`, and
`--plain` to turn official-document mode off for a generic conversion.

## 3. Filling forms — applications with blanks

This is the most repetitive job of all — the one where you fill in the same
application twenty times.

**Order matters. Start by asking what can be filled.**

```bash
npx -y kordoc@^4 fill application.hwpx --dry-run
```

You get the list of labels. Build your values from that list as JSON.

```bash
npx -y kordoc@^4 fill application.hwpx -j values.json -o filled.hwpx
```

- **Always pass values via `-j`.** `-f 'k=v,...'` works too, but the values end
  up in your shell history and in the process list. Given what goes into an
  application form, the reason is obvious.
- Original fonts, sizes and alignment are **preserved exactly**. It doesn't look
  filled-in by a machine.
- Multi-line values use `\n` inside the JSON string.

> **If the same label appears in several places, the default is to fill all of
> them.** That's deliberate — repeating forms need it — but on some templates it
> will fill a cell you didn't mean. On a form you're using for the first time,
> check with `--dry-run` how many times a label occurs.

### Seals

```bash
npx -y kordoc@^4 seal application.hwpx --image seal.png --anchor "(인)" -o sealed.hwpx
```

Finds an anchor phrase like "(인)" and floats the image **in front of the text**.
Meaning tables and pages never grow — no more discovering that stamping the form
pushed it onto an extra page. Use a transparent-background PNG.

## 4. Editing — while keeping the original formatting

For when only the wording of a received document needs to change.

```bash
npx -y kordoc@^4 original.hwpx -o edit.md                     # ① to Markdown
# ② change the content in edit.md
npx -y kordoc@^4 patch original.hwpx edit.md -o revised.hwpx  # ③ back in
```

In ② **change content only.** Keep structural moves and deletions to a minimum.
Fonts, tables, objects and layout stay as they were in the original; only the
text is written back in place.

## Before you hand it over — validate and preview

**Anything you generated or patched gets checked before it goes out.**

```bash
npx -y kordoc@^4 validate result.hwpx                       # structure check
npx -y kordoc@^4 render result.hwpx --reflow -o preview.svg  # look at it
```

`validate` inspects the ZIP structure, required parts and XML well-formedness —
**this is where you catch the reasons a Hancom Docs upload would be rejected.**
`render` draws the layout as SVG; files kordoc produced have no layout cache, so
`--reflow` is required for them.

Comparing two documents to produce a **신구대조표** (old/new comparison table)
works as well — you get a diff at the article and paragraph level.

## Running it in HyperTeams

A fixed conversion has no judgement in it, so it's **`terminal`** — the same
slot as the collection step in
[Case study — the content factory](/guide/ht-case-factory).

```
Mondays 08:00  ·  kind: terminal
npx -y kordoc@^4 ./notices/*.hwp -d ./notices-md/
```

When something has to **decide** what goes in the blanks, that part is a `task`.

```
1. terminal — extract labels from the form with --dry-run
2. task     — find the values in internal material, write values.json
3. terminal — fill, then validate
4. a person — check it and submit
```

**Step 4 is a person** for the same reason as in [Guardrails](/guide/ha-guardrails).
Submission can't be undone.

### Using it from Connect

kordoc also attaches as an MCP server. That's the route when you want workspace
members handling hwp files inside a conversation.

```bash
npx -y kordoc@^4 setup
```

An interactive wizard registers it with your client. For the workspace side, see
[Connecting MCP servers](/guide/cn-mcp) and [Tool settings](/guide/cn-tool-settings).
It adds eleven tools, so the warnings in [When there are too many
tools](/guide/mcp-too-many-tools) apply directly.

## Things to be careful about

### These forms carry personal data

Applications and HR forms contain national ID numbers, bank accounts, phone
numbers.

```
□ Is values.json being committed to the repository?
□ Is the filled result sitting in a shared folder?
□ Did the values end up verbatim in a chat log?
```

The closing warning of [Turning documents into
material](/guide/ht-documents) gets stronger here. **The working directory is
the agent's reach**, and if the system is [registered with
Connect](/guide/cn-systems), workspace members reach it too.

### Don't overwrite the original

**Always write to a new file with `-o`** — filling, patching and sealing alike.
Getting a blank official form again is often more trouble than it sounds.

### Password-protected and DRM files won't open

DRM-wrapped documents distributed by an agency, or password-protected files,
won't parse. That is not something to work around — it's **a signal to find
another route.**

### Check the numbers and the tables

Same as the previous chapter. If money, dates or quantities drive the decision,
**check the original.** "Always verify numbers" from [Things to
watch](/guide/ai-cautions) applies with particular force to official documents.

---

## Check yourself

**1. Can you edit a `.hwp` file and write it back out in the same format?**

<details>
<summary>Answer</summary>

**You can read it, but you can't write that format back.** Everything generated,
filled or patched comes out as `.hwpx`. If `.hwp` is required, a person re-saves
it from Hangul at the end.
</details>

**2. Why pass form values via `-j` rather than `-f`?**

<details>
<summary>Answer</summary>

**Because the values land in shell history and the process list.** What goes
into an application form is usually personal data — ID numbers, bank accounts.
</details>

**3. What do you do with a generated hwpx before handing it to someone?**

<details>
<summary>Answer</summary>

**Run `validate` on it.** It checks the ZIP structure, required parts and XML
form, catching the reasons a Hancom Docs upload would be rejected. If the layout
is in doubt, look at it with `render --reflow` too.
</details>

---

**That's the end of the Extending it part.** If something is stuck →
[Troubleshooting](/guide/ht-troubleshooting) · [Guide contents](/guide)
