K2F Create, design, edit elegant Word (docx), PDF, fillable AcroForm PDF, and Adobe InDesign (IDML) with K2F. K2F designed for agents to design and edit elegant documents precisely and effortlessly. Use with AI agents when you need aesthetic documents—menus, certificates, planners, invitations, worksheets, and more. You can start from Gallery templates. A is a ZIP: you edit a semantic JSON tree (meaning, not coordinates); the engine / s an immutable render lock. One reference engine → pixel-identical output everywhere. Choose the workflow Read one reference file for the task. Do not load all…

Line one\\\\nLine two' --find \"Line two\"\n # [9, 17] (the newline between lines is byte index 8)\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport sys\n\n\ndef byte_range(text: str, find: str, occurrence: int = 0) -> list[int]:\n if not find:\n raise ValueError(\"--find must be non-empty\")\n encoded = text.encode(\"utf-8\")\n needle = find.encode(\"utf-8\")\n start = -1\n cursor = 0\n for _ in range(occurrence + 1):\n start = encoded.find(needle, cursor)\n if start \u003c 0:\n raise ValueError(f\"substring not found (occurrence {occurrence}): {find!r}\")\n cursor = start + 1\n end = start + len(needle)\n return [start, end]\n\n\ndef main() -> int:\n parser = argparse.ArgumentParser(\n description=\"Compute UTF-8 byte [start, end) for a K2F text modifier range\"\n )\n parser.add_argument(\"--text\", required=True, help=\"Exact text node value\")\n parser.add_argument(\"--find\", required=True, help=\"Substring to mark\")\n parser.add_argument(\n \"--nth\",\n type=int,\n default=0,\n help=\"0-based occurrence if the substring repeats (default 0)\",\n )\n args = parser.parse_args()\n try:\n rng = byte_range(args.text, args.find, args.nth)\n except ValueError as e:\n print(f\"error: {e}\", file=sys.stderr)\n return 1\n print(json.dumps(rng))\n return 0\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":1893,"content_sha256":"fde2d759907b4fe6497e62d2871f67b4c823281774d1c811ea4708d60faec99b"},{"filename":"scripts/pack_verify.py","content":"#!/usr/bin/env python3\n\"\"\"Pack → compile → verify an unpacked K2F author directory.\n\nViewers paint document.K2F.lock, not source/ JSON — run this after every\ncontent/ or theme edit so the output .K2F and renders match the author tree.\n\nUses the `k2f` CLI on PATH or K2F_CLI. CLI stderr/stdout are forwarded so agents\ncan map failures via references/writing/errors.md.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport os\nimport re\nimport shutil\nimport subprocess\nimport sys\nfrom pathlib import Path\n\nPAGES_RE = re.compile(r\"pages=(\\d+)\")\nSOURCE_ROOT_WARN_SUFFIXES = (\".K2F\", \".k2f\", \".pdf\", \".png\", \".docx\", \".pptx\")\n\n\ndef k2f_binary() -> list[str]:\n env_cli = os.environ.get(\"K2F_CLI\")\n if env_cli:\n path = Path(env_cli).expanduser().resolve()\n if path.is_file():\n return [str(path)]\n print(f\"error: K2F_CLI is not a file: {path}\", file=sys.stderr)\n sys.exit(1)\n which = shutil.which(\"k2f\")\n if which:\n return [which]\n print(\n \"error: `k2f` CLI not found on PATH.\\n\"\n \"Install: pip install k2f\\n\"\n \"Or set K2F_CLI to the binary path.\\n\"\n \"This script does not search a git checkout or cargo target directory.\",\n file=sys.stderr,\n )\n sys.exit(1)\n\n\ndef run(cmd: list[str], cwd: Path | None = None) -> subprocess.CompletedProcess[str]:\n print(\"+\", \" \".join(cmd), flush=True)\n proc = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True)\n if proc.stdout:\n print(proc.stdout, end=\"\" if proc.stdout.endswith(\"\\n\") else \"\\n\", flush=True)\n if proc.stderr:\n print(\n proc.stderr,\n end=\"\" if proc.stderr.endswith(\"\\n\") else \"\\n\",\n file=sys.stderr,\n flush=True,\n )\n if proc.returncode != 0:\n sys.exit(proc.returncode)\n return proc\n\n\ndef parse_pages(stderr: str) -> int | None:\n matches = PAGES_RE.findall(stderr)\n if not matches:\n return None\n return int(matches[-1])\n\n\ndef extra_render_path(primary: Path, page: int) -> Path:\n return primary.with_name(f\"{primary.stem}-{page}{primary.suffix}\")\n\n\ndef resolve_render_path(render: Path, output: Path) -> Path:\n \"\"\"Bare filename (preview.png) → {output.parent}/tmp/. Otherwise CWD-relative.\"\"\"\n path = render.expanduser()\n if not path.is_absolute() and len(path.parts) == 1:\n return (output.parent / \"tmp\" / path).resolve()\n return path.resolve()\n\n\ndef path_is_inside(inner: Path, outer: Path) -> bool:\n try:\n inner.resolve().relative_to(outer.resolve())\n return True\n except ValueError:\n return False\n\n\ndef warn_source_root_extras(source: Path) -> None:\n extras = sorted(\n p.name\n for p in source.iterdir()\n if p.is_file() and p.name.endswith(SOURCE_ROOT_WARN_SUFFIXES)\n )\n if not extras:\n return\n listed = \", \".join(extras)\n print(\n f\"warning: deliverable/debug files in author dir (move to workspace root or tmp/): {listed}\",\n file=sys.stderr,\n flush=True,\n )\n\n\ndef warn_path_inside_source(source: Path, path: Path, what: str) -> None:\n if not path_is_inside(path, source):\n return\n print(\n f\"warning: {what} is inside the author directory; write deliverables at the workspace \"\n \"root (e.g. ./out/doc/doc.K2F, tmp/preview.png), not under source/\",\n file=sys.stderr,\n flush=True,\n )\n\n\ndef main() -> int:\n parser = argparse.ArgumentParser(description=\"Pack, compile, and verify a K2F source dir\")\n parser.add_argument(\"source_dir\", type=Path, help=\"Unpacked package directory\")\n parser.add_argument(\n \"-o\",\n \"--output\",\n type=Path,\n required=True,\n help=\"Output .K2F path\",\n )\n parser.add_argument(\n \"--render\",\n type=Path,\n metavar=\"PNG\",\n help=\"Optional: render after verify. A bare filename is written under \"\n \"tmp/ next to the output .K2F (e.g. --render preview.png → \"\n \"\u003cout-dir>/tmp/preview.png). Paths with a directory stay CWD-relative. \"\n \"The --page index is the primary file; extra pages write preview-1.png …\",\n )\n parser.add_argument(\n \"--page\",\n type=int,\n default=0,\n help=\"Page index for --render (default 0)\",\n )\n parser.add_argument(\n \"--expect-pages\",\n type=int,\n default=None,\n metavar=\"N\",\n help=\"Fail if compile reports a page count other than N (posters: 1)\",\n )\n args = parser.parse_args()\n\n source = args.source_dir.expanduser().resolve()\n if not source.is_dir():\n print(f\"error: not a directory: {source}\", file=sys.stderr)\n return 1\n for required in (\"manifest.json\", \"content/root.json\", \"styles/theme.json\"):\n if not (source / required).is_file():\n print(f\"error: missing {required} under {source}\", file=sys.stderr)\n return 1\n fonts = source / \"assets\" / \"fonts\"\n if not fonts.is_dir() or not any(fonts.iterdir()):\n print(f\"error: no fonts under {fonts}\", file=sys.stderr)\n return 1\n\n output = args.output.expanduser().resolve()\n output.parent.mkdir(parents=True, exist_ok=True)\n warn_path_inside_source(source, output, \"-o\")\n warn_source_root_extras(source)\n\n prefix = k2f_binary()\n print(f\"using: {' '.join(prefix)}\", flush=True)\n\n run([*prefix, \"pack\", str(source), \"-o\", str(output)])\n compile_proc = run([*prefix, \"compile\", str(output)])\n pages = parse_pages(compile_proc.stderr)\n if args.expect_pages is not None:\n if pages is None:\n print(\n \"error: compile did not print pages=N — upgrade `k2f` CLI (pip install -U k2f)\",\n file=sys.stderr,\n )\n return 1\n if pages != args.expect_pages:\n print(\n f\"error: expected {args.expect_pages} page(s), got {pages} \"\n f\"(shrink layout or raise --expect-pages)\",\n file=sys.stderr,\n )\n return 1\n run([*prefix, \"verify\", str(output)])\n\n if args.render is not None:\n render_out = resolve_render_path(args.render, output)\n warn_path_inside_source(source, render_out, \"--render\")\n render_out.parent.mkdir(parents=True, exist_ok=True)\n run(\n [\n *prefix,\n \"render\",\n str(output),\n \"--page\",\n str(args.page),\n \"-o\",\n str(render_out),\n ]\n )\n print(f\"ok: rendered {render_out}\", flush=True)\n if pages is not None and pages > 1:\n for i in range(pages):\n if i == args.page:\n continue\n extra = extra_render_path(render_out, i)\n run(\n [\n *prefix,\n \"render\",\n str(output),\n \"--page\",\n str(i),\n \"-o\",\n str(extra),\n ]\n )\n print(f\"ok: rendered {extra}\", flush=True)\n\n if pages is not None:\n print(f\"ok: {output} pages={pages}\")\n else:\n print(f\"ok: {output}\")\n return 0\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":7373,"content_sha256":"2d542031ad4e7fe6aac8df8fa8cacabdaae6d79f9e2acb1e2953dfbaed273c0d"},{"filename":"scripts/publish.py","content":"#!/usr/bin/env python3\n\"\"\"Preflight and POST a .K2F package to POST /api/publish.\n\nAvoids fragile hand-rolled curl: binary body, application/zip, lock hash check, 8 MiB cap.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nimport re\nimport sys\nimport urllib.error\nimport urllib.request\nimport zipfile\nfrom pathlib import Path\n\nMAX_PACKAGE_BYTES = 8 * 1024 * 1024\nHASH_RE = re.compile(r\"^[0-9a-f]{64}$\")\nLOCK_NAME = \"document.K2F.lock\"\n\n\ndef resolve_origin(args_origin: str | None) -> str:\n origin = args_origin or os.environ.get(\"K2F_PUBLISH_ORIGIN\")\n if not origin:\n raise SystemExit(\n \"publish origin required.\\n\"\n \"Pass --origin https://your-k2f-site.example or set K2F_PUBLISH_ORIGIN.\\n\"\n \"Embedding with \u003ck2f-viewer> does not require publish.\"\n )\n return origin.rstrip(\"/\")\n\n\ndef appearance_hash_from_package(path: Path) -> str:\n data = path.read_bytes()\n if len(data) == 0 or len(data) > MAX_PACKAGE_BYTES:\n raise SystemExit(\n f\"invalid package size: {len(data)} bytes (max {MAX_PACKAGE_BYTES})\"\n )\n if len(data) \u003c 2 or data[0] != 0x50 or data[1] != 0x4B:\n raise SystemExit(\"expected ZIP package (PK magic)\")\n\n try:\n with zipfile.ZipFile(path, \"r\") as zf:\n try:\n lock_raw = zf.read(LOCK_NAME)\n except KeyError as e:\n raise SystemExit(f\"zip missing {LOCK_NAME}\") from e\n except zipfile.BadZipFile as e:\n raise SystemExit(f\"expected ZIP package: {e}\") from e\n\n try:\n lock = json.loads(lock_raw.decode(\"utf-8\"))\n except (UnicodeDecodeError, json.JSONDecodeError) as e:\n raise SystemExit(f\"package lock missing appearance_hash: {e}\") from e\n\n hash_val = lock.get(\"appearance_hash\")\n if not isinstance(hash_val, str) or not HASH_RE.match(hash_val):\n raise SystemExit(\"package lock missing appearance_hash\")\n return hash_val\n\n\ndef publish(path: Path, origin: str) -> dict:\n body = path.read_bytes()\n url = f\"{origin}/api/publish\"\n req = urllib.request.Request(\n url,\n data=body,\n method=\"POST\",\n headers={\"Content-Type\": \"application/zip\"},\n )\n try:\n with urllib.request.urlopen(req) as resp:\n raw = resp.read().decode(\"utf-8\")\n status = resp.status\n except urllib.error.HTTPError as e:\n err_body = e.read().decode(\"utf-8\", errors=\"replace\")\n print(f\"publish HTTP {e.code}: {err_body}\", file=sys.stderr)\n raise SystemExit(1) from e\n except urllib.error.URLError as e:\n print(f\"publish request failed: {e}\", file=sys.stderr)\n raise SystemExit(1) from e\n\n if status \u003c 200 or status >= 300:\n print(f\"publish HTTP {status}: {raw}\", file=sys.stderr)\n raise SystemExit(1)\n\n try:\n return json.loads(raw)\n except json.JSONDecodeError as e:\n print(f\"publish response json: {e}\\n{raw}\", file=sys.stderr)\n raise SystemExit(1) from e\n\n\ndef main() -> None:\n parser = argparse.ArgumentParser(\n description=\"Publish a locked .K2F package to POST /api/publish\"\n )\n parser.add_argument(\"package\", type=Path, help=\"Path to .K2F ZIP\")\n parser.add_argument(\n \"--origin\",\n default=None,\n help=\"Publish API origin (required unless --dry-run; or set K2F_PUBLISH_ORIGIN)\",\n )\n parser.add_argument(\n \"--dry-run\",\n action=\"store_true\",\n help=\"Preflight only: print appearance_hash, do not POST\",\n )\n args = parser.parse_args()\n\n path = args.package\n if not path.is_file():\n raise SystemExit(f\"file not found: {path}\")\n\n appearance_hash = appearance_hash_from_package(path)\n if args.dry_run:\n print(appearance_hash)\n return\n\n origin = resolve_origin(args.origin)\n result = publish(path, origin)\n print(json.dumps(result, indent=2))\n rel = result.get(\"url\")\n if isinstance(rel, str) and rel.startswith(\"/\"):\n print(f\"absolute: {origin}{rel}\")\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":4075,"content_sha256":"83cee54bcafa477aacc96c14a8fc2c32d0156fdb4a733c7df3649ae31481b842"},{"filename":"starter/assets/fonts/licenses/Roboto-Apache.txt","content":"Roboto Font\nCopyright 2011 Google Inc. All Rights Reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nSource: https://fonts.google.com/specimen/Roboto\n","content_type":"text/plain; charset=utf-8","language":null,"size":635,"content_sha256":"5b4e7dbd455f2bb8c396284b0ea17b9657d0a6d394177cf88dab2f016d18c8d7"},{"filename":"starter/changelog.json","content":"{\"entries\": []}\n","content_type":"application/json; charset=utf-8","language":"json","size":16,"content_sha256":"eb9689f4e89f0b8b88f6fde235f1d5d9329c3056a21e6f451e36f23604ff8394"},{"filename":"starter/content/root.json","content":"{\n \"id\": \"root\",\n \"role\": \"document\",\n \"content\": {\n \"type\": \"container\",\n \"value\": {\n \"children\": []\n }\n }\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":128,"content_sha256":"f91860a57c0b038ee7d3384e779aa9684f4b9aeca9c11f4591210c42eab65525"},{"filename":"starter/manifest.json","content":"{\n \"title\": \"Untitled\",\n \"created_at\": 0,\n \"canvas_mode\": \"paged\",\n \"page_config\": {\n \"width\": 595000,\n \"height\": 842000,\n \"margin\": [56000, 56000, 56000, 56000]\n },\n \"engine_version\": \"0.1.0\"\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":210,"content_sha256":"77240b898a5a44bc4122dddd57291a87a1c4e3ff7925e35331550298f684540d"},{"filename":"starter/styles/theme.json","content":"{\n \"font_aliases\": {\n \"Roboto-Regular\": \"Roboto-Regular\"\n },\n \"palette\": {\n \"ink\": \"#151515\",\n \"paper\": \"#FFFFFF\",\n \"muted\": \"#5F6368\",\n \"accent\": \"#151515\",\n \"warning_bg\": \"#FFEBEE\",\n \"warning_ink\": \"#C62828\",\n \"header_bg\": \"#151515\",\n \"header_ink\": \"#FFFFFF\",\n \"alt_row\": \"#F5F5F7\",\n \"signature\": \"#F5F5F7\",\n \"rule\": \"#D2D2D7\",\n \"disabled\": \"#15151561\"\n },\n \"primitives\": {\n \"surfaces\": {\n \"paper\": { \"type\": \"solid\", \"color\": \"paper\" },\n \"rule\": { \"type\": \"solid\", \"color\": \"rule\" },\n \"signature\": { \"type\": \"solid\", \"color\": \"signature\" },\n \"header_bg\": { \"type\": \"solid\", \"color\": \"header_bg\" },\n \"warning_bg\": { \"type\": \"solid\", \"color\": \"warning_bg\" }\n },\n \"corners\": { \"none\": 0, \"small\": 4000, \"medium\": 12000 },\n \"borders\": {\n \"subtle\": { \"color\": \"#1515151A\", \"width_pt\": 500 },\n \"subtle_bottom\": { \"color\": \"#1515151A\", \"width_pt\": 500, \"edges\": [\"bottom\"] },\n \"subtle_hbar\": { \"color\": \"#1515151A\", \"width_pt\": 500, \"edges\": [\"top\", \"bottom\"] },\n \"contrast\": { \"color\": \"#1515154D\", \"width_pt\": 1000 }\n },\n \"shadows\": {\n \"elevation.1\": {\n \"layers\": [\n {\n \"blur_radius_pt\": 4000,\n \"color\": \"#0000001A\",\n \"offset_x_pt\": 0,\n \"offset_y_pt\": 2000,\n \"spread_radius_pt\": 0\n }\n ]\n }\n }\n },\n \"modifiers\": {\n \"precedence\": [\"emphasis\", \"link\", \"math\"],\n \"styles\": {\n \"emphasis\": {\n \"strong\": { \"bold\": true },\n \"emphasis\": { \"italic\": true }\n },\n \"link\": {\n \"default\": { \"underline\": true, \"color\": \"accent\" }\n },\n \"math\": {\n \"inline\": { \"color\": \"ink\" }\n },\n \"underline\": {\n \"default\": { \"underline\": true }\n },\n \"strikethrough\": {\n \"default\": { \"strikethrough\": true }\n },\n \"subscript\": {\n \"default\": {}\n },\n \"superscript\": {\n \"default\": {}\n },\n \"syntax_highlight\": {\n \"keyword\": { \"color\": \"accent\", \"bold\": true }\n }\n }\n },\n \"roles\": {\n \"default\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1350,\n \"color\": \"ink\"\n },\n \"document\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1350,\n \"color\": \"ink\",\n \"box_decoration\": { \"background\": \"paper\" }\n },\n \"body\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1350,\n \"color\": \"ink\",\n \"variants\": {\n \"on_dark\": { \"text_overrides\": { \"color\": \"header_ink\" } },\n \"end\": { \"text_overrides\": { \"text_align\": \"end\" } }\n }\n },\n \"image\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1350,\n \"color\": \"ink\",\n \"self_align\": \"start\",\n \"variants\": {\n \"cover\": { \"image_fit\": \"cover\", \"self_align\": \"stretch\" }\n }\n },\n \"h1\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 24000,\n \"line_height_mult\": 1250,\n \"color\": \"ink\",\n \"bold\": true,\n \"variants\": {\n \"on_dark\": { \"text_overrides\": { \"color\": \"header_ink\" } }\n }\n },\n \"h2\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 18000,\n \"line_height_mult\": 1300,\n \"color\": \"ink\",\n \"bold\": true,\n \"variants\": {\n \"on_dark\": { \"text_overrides\": { \"color\": \"header_ink\" } },\n \"end\": { \"text_overrides\": { \"text_align\": \"end\" } }\n }\n },\n \"h3\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 14000,\n \"line_height_mult\": 1350,\n \"color\": \"ink\",\n \"bold\": true\n },\n \"h4\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 12000,\n \"line_height_mult\": 1400,\n \"color\": \"ink\",\n \"bold\": true\n },\n \"warning\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1400,\n \"color\": \"warning_ink\",\n \"box_decoration\": {\n \"background\": \"warning_bg\",\n \"corner_radius\": \"small\",\n \"padding_pt\": 12000\n }\n },\n \"badge\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 9000,\n \"line_height_mult\": 1200,\n \"color\": \"ink\",\n \"bold\": true,\n \"self_align\": \"start\",\n \"box_decoration\": {\n \"background\": \"signature\",\n \"corner_radius\": \"small\",\n \"padding_pt\": { \"top\": 3000, \"right\": 8000, \"bottom\": 3000, \"left\": 8000 }\n }\n },\n \"section\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1350,\n \"color\": \"ink\",\n \"variants\": {\n \"banner\": {\n \"box_decoration\": {\n \"background\": \"header_bg\",\n \"padding_pt\": { \"top\": 24000, \"right\": 36000, \"bottom\": 24000, \"left\": 36000 }\n }\n }\n }\n },\n \"page_shell\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1350,\n \"color\": \"ink\",\n \"box_decoration\": {\n \"padding_pt\": 36000\n },\n \"variants\": {\n \"flush\": {\n \"box_decoration\": {\n \"padding_pt\": 0\n }\n }\n }\n },\n \"table\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1400,\n \"color\": \"ink\",\n \"variants\": {\n \"ruled\": { \"box_decoration\": { \"border\": \"subtle_hbar\" } }\n }\n },\n \"table_header_cell\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1400,\n \"color\": \"header_ink\",\n \"box_decoration\": {\n \"background\": \"header_bg\",\n \"corner_radius\": \"small\",\n \"padding_pt\": 6000\n },\n \"variants\": {\n \"center\": { \"self_align\": \"center\" },\n \"end\": { \"text_overrides\": { \"text_align\": \"end\" } },\n \"bottom\": { \"box_decoration\": { \"border\": \"subtle_bottom\" } },\n \"hbar\": { \"box_decoration\": { \"border\": \"subtle_hbar\" } },\n \"compact\": { \"box_decoration\": { \"padding_pt\": 3000 } }\n }\n },\n \"table_row_cell\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1400,\n \"color\": \"ink\",\n \"box_decoration\": { \"padding_pt\": 6000 },\n \"variants\": {\n \"center\": { \"self_align\": \"center\" },\n \"end\": { \"text_overrides\": { \"text_align\": \"end\" } },\n \"bottom\": { \"box_decoration\": { \"border\": \"subtle_bottom\" } },\n \"hbar\": { \"box_decoration\": { \"border\": \"subtle_hbar\" } },\n \"compact\": { \"box_decoration\": { \"padding_pt\": 3000 } },\n \"on_dark\": {\n \"text_overrides\": { \"color\": \"header_ink\" },\n \"box_decoration\": { \"padding_pt\": 3000 }\n }\n }\n },\n \"list_item\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1500,\n \"color\": \"ink\",\n \"list_style\": {\n \"bullet_glyph\": \"-\",\n \"depth_indent_pt\": 18000,\n \"marker_box_width_pt\": 18000,\n \"marker_gap_pt\": 4000,\n \"number_suffix\": \".\"\n }\n },\n \"code\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 10500,\n \"line_height_mult\": 1400,\n \"color\": \"ink\",\n \"box_decoration\": {\n \"background\": \"signature\",\n \"corner_radius\": \"small\",\n \"padding_pt\": 8000\n }\n },\n \"quote\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1600,\n \"color\": \"muted\",\n \"box_decoration\": {\n \"padding_pt\": { \"top\": 0, \"right\": 0, \"bottom\": 10000, \"left\": 16000 }\n }\n },\n \"math\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1600,\n \"color\": \"ink\",\n \"text_align\": \"center\"\n },\n \"running_header\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 9000,\n \"line_height_mult\": 1200,\n \"color\": \"muted\",\n \"variants\": {\n \"end\": { \"text_overrides\": { \"text_align\": \"end\" } }\n }\n },\n \"running_footer\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 9000,\n \"line_height_mult\": 1200,\n \"color\": \"muted\",\n \"variants\": {\n \"end\": { \"text_overrides\": { \"text_align\": \"end\" } }\n }\n },\n \"signature_block\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1400,\n \"color\": \"muted\",\n \"box_decoration\": {\n \"background\": \"signature\",\n \"padding_pt\": 16000\n }\n },\n \"form_field\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1400,\n \"color\": \"ink\",\n \"box_decoration\": {\n \"padding_pt\": { \"top\": 2000, \"right\": 4000, \"bottom\": 2000, \"left\": 4000 },\n \"border\": \"subtle_bottom\"\n },\n \"variants\": {\n \"underline\": { \"box_decoration\": { \"border\": \"subtle_bottom\" } },\n \"box\": { \"box_decoration\": { \"border\": \"subtle\", \"corner_radius\": \"small\" } },\n \"checkbox\": { \"box_decoration\": { \"border\": \"contrast\", \"corner_radius\": \"small\" } }\n }\n },\n \"rule\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 2000,\n \"line_height_mult\": 1000,\n \"color\": \"muted\",\n \"box_decoration\": { \"background\": \"rule\" }\n },\n \"card\": {\n \"font_family\": \"Roboto-Regular\",\n \"font_size\": 11000,\n \"line_height_mult\": 1600,\n \"color\": \"ink\",\n \"box_decoration\": {\n \"background\": \"paper\",\n \"corner_radius\": \"medium\",\n \"padding_pt\": 16000\n },\n \"variants\": {\n \"raised\": {\n \"box_decoration\": {\n \"background\": \"paper\",\n \"corner_radius\": \"medium\",\n \"padding_pt\": 16000,\n \"shadow\": \"elevation.1\"\n }\n },\n \"on_dark\": {\n \"text_overrides\": { \"color\": \"header_ink\" },\n \"box_decoration\": {\n \"background\": \"header_bg\",\n \"corner_radius\": \"medium\",\n \"padding_pt\": 16000\n }\n }\n }\n }\n }\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":10080,"content_sha256":"2c3a292d7513e22f47e266c96fa8f3791e65984825ef9a29d1231d8a0dc09ec1"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"K2F","type":"text"}]},{"type":"paragraph","content":[{"text":"Create, design, edit elegant Word (docx), PDF, fillable AcroForm PDF, and Adobe InDesign (IDML) with K2F. K2F designed for agents to design and edit elegant documents precisely and effortlessly. Use with AI agents when you need aesthetic documents—menus, certificates, planners, invitations, worksheets, and more. You can start from ","type":"text"},{"text":"Gallery","type":"text","marks":[{"type":"link","attrs":{"href":"https://k2f.dev/gallery","title":null}}]},{"text":" templates.","type":"text"}]},{"type":"paragraph","content":[{"text":"A ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":" is a ZIP: you edit a semantic JSON tree (meaning, not coordinates); the engine ","type":"text"},{"text":"pack","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"compile","type":"text","marks":[{"type":"code_inline"}]},{"text":"s an immutable render lock. One reference engine → pixel-identical output everywhere.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Choose the workflow","type":"text"}]},{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":"one","type":"text","marks":[{"type":"strong"}]},{"text":" reference file for the task. Do not load all workflows.","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Task","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Read","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Create or update a ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":" (CV, flyer, slide deck, poster, report, patch by node id)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/writing.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Convert Markdown ↔ K2F","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/converting-markdown.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/converting-markdown.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Export PDF from the published lock","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/exporting-pdf.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/exporting-pdf.md","title":null}}]},{"text":" — bytes / looks wrong: ","type":"text"},{"text":"pdf-contract.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/exporting-pdf/pdf-contract.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Export PPTX from the published lock","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/exporting-pptx.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/exporting-pptx.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Export DOCX from the published lock","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/exporting-docx.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/exporting-docx.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Export IDML from the published lock","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/exporting-idml.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/exporting-idml.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Publish permanent ","type":"text"},{"text":"/v/{appearance_hash}","type":"text","marks":[{"type":"code_inline"}]},{"text":" link","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/publishing.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/publishing.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Embed ","type":"text"},{"text":"\u003ck2f-viewer>","type":"text","marks":[{"type":"code_inline"}]},{"text":" in a web app","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/embedding-viewer.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/embedding-viewer.md","title":null}}]},{"text":" (","type":"text"},{"text":"npm i @openk2f/k2f","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Writing","type":"text","marks":[{"type":"strong"}]},{"text":" (default): one loop — get a workspace (","type":"text"},{"text":"source/","type":"text","marks":[{"type":"code_inline"}]},{"text":" author package + deliverables at the root), edit JSON like source code, copy shapes from ","type":"text"},{"text":"catalog/content/ex_*.json","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/content/","title":null}},{"type":"code_inline"}]},{"text":" into root ","type":"text"},{"text":"children","type":"text","marks":[{"type":"code_inline"}]},{"text":" (do not replace ","type":"text"},{"text":"content/root.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" with a fragment), and ","type":"text"},{"text":"scripts/pack_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":". The author directory is ","type":"text"},{"text":"k2f unpack … -o ./out/doc/source","type":"text","marks":[{"type":"code_inline"}]},{"text":" (user ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":" or a Gallery package), or ","type":"text"},{"text":"starter/","type":"text","marks":[{"type":"link","attrs":{"href":"starter/","title":null}},{"type":"code_inline"}]},{"text":" via ","type":"text"},{"text":"scripts/init_package.py --workspace ./out/doc","type":"text","marks":[{"type":"code_inline"}]},{"text":" when nothing matches.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Do ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" use ","type":"text"},{"text":"Editor.insert_node","type":"text","marks":[{"type":"code_inline"}]},{"text":" on an unpacked author directory — that API follows a narrower agent dialect; JSON authoring uses the full format schema validated at pack time.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Text ","type":"text"},{"text":"modifiers","type":"text","marks":[{"type":"code_inline"}]},{"text":" need ","type":"text"},{"text":"intent","type":"text","marks":[{"type":"code_inline"}]},{"text":" plus UTF-8 ","type":"text"},{"text":"byte","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"range","type":"text","marks":[{"type":"code_inline"}]},{"text":" — always run ","type":"text"},{"text":"scripts/modifier_range.py","type":"text","marks":[{"type":"link","attrs":{"href":"scripts/modifier_range.py","title":null}},{"type":"code_inline"}]},{"text":"; never hand-count (especially across ","type":"text"},{"text":"\\n","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fillable blanks/checkboxes: copy ","type":"text"},{"text":"catalog/content/ex_form.json","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/content/ex_form.json","title":null}},{"type":"code_inline"}]},{"text":" (never ","type":"text"},{"text":"____","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"□","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Gallery URL (","type":"text"},{"text":"\u003corigin>/gallery/\u003cslug>","type":"text","marks":[{"type":"code_inline"}]},{"text":") or package URL: fetch ","type":"text"},{"text":"\u003corigin>/api/gallery/templates/\u003cslug>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (or package URL) to a ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":" on disk and ","type":"text"},{"text":"k2f unpack","type":"text","marks":[{"type":"code_inline"}]},{"text":" — do not load the ZIP into context. ","type":"text"},{"text":"MCP","type":"text","marks":[{"type":"strong"}]},{"text":" is optional. Writing does not require it and does not install it. If a site MCP with ","type":"text"},{"text":"list_templates","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"download_template","type":"text","marks":[{"type":"code_inline"}]},{"text":" is already connected, ","type":"text"},{"text":"download_template","type":"text","marks":[{"type":"code_inline"}]},{"text":" returns the same kind of ","type":"text"},{"text":"packageUrl","type":"text","marks":[{"type":"code_inline"}]},{"text":"; fetch + unpack as in step 2 of ","type":"text"},{"text":"writing.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing.md","title":null}}]},{"text":". Missing tools, kind mismatch, or download failure → continue from ","type":"text"},{"text":"starter/","type":"text","marks":[{"type":"code_inline"}]},{"text":"; do not stop the task.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"What K2F is","type":"text"}]},{"type":"paragraph","content":[{"text":"PDF is unreadable and uneditable for AI. HTML/CSS renders differently on every device. K2F fixes both: agents write plain JSON ","type":"text"},{"text":"meaning","type":"text","marks":[{"type":"em"}]},{"text":", and one reference engine turns that meaning into pixel-identical output everywhere.","type":"text"}]},{"type":"paragraph","content":[{"text":"Instead of positioning content with coordinates:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"{\"text\": \"WARNING!\", \"x\": 100, \"y\": 50, \"color\": \"red\", \"bold\": true}","type":"text"}]},{"type":"paragraph","content":[{"text":"K2F authors describe meaning:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"{\"id\": \"doc.warning\", \"role\": \"warning\", \"content\": {\"type\": \"text\", \"value\": \"WARNING!\"}}","type":"text"}]},{"type":"paragraph","content":[{"text":"Every ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":" file is a ZIP holding two states:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"State A — semantic tree","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"content/root.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", mutable, the file you edit). Every node has a stable dotted ","type":"text"},{"text":"id","type":"text","marks":[{"type":"code_inline"}]},{"text":", a ","type":"text"},{"text":"role","type":"text","marks":[{"type":"code_inline"}]},{"text":", an optional ","type":"text"},{"text":"variant","type":"text","marks":[{"type":"code_inline"}]},{"text":", and optional ","type":"text"},{"text":"modifiers","type":"text","marks":[{"type":"code_inline"}]},{"text":" (inline emphasis/link/math on a byte range). No coordinates, no colors, no font sizes — those live only in ","type":"text"},{"text":"styles/theme.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", keyed by role/variant.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"State C — render lock","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"document.K2F.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":", immutable, generated). Exact geometry, paint operations, and integrity hashes. Every viewer and every PDF export paints ","type":"text"},{"text":"this","type":"text","marks":[{"type":"em"}]},{"text":", not the tree.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"The engine — not the agent — turns A into C by running ","type":"text"},{"text":"pack","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"compile","type":"text","marks":[{"type":"code_inline"}]},{"text":". Other package paths: ","type":"text"},{"text":"manifest.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" (page size, margins), ","type":"text"},{"text":"assets/fonts|images|data/*","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"changelog.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" (edit history), optional ","type":"text"},{"text":"signatures/v1.json","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"paragraph","content":[{"text":"When handing a ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":" to the user, point them to ","type":"text"},{"text":"k2f.dev/playground","type":"text","marks":[{"type":"link","attrs":{"href":"https://k2f.dev/playground","title":null}}]},{"text":" (browser) or ","type":"text"},{"text":"k2f.dev/download","type":"text","marks":[{"type":"link","attrs":{"href":"https://k2f.dev/download","title":null}}]},{"text":" (desktop app).","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Setup","type":"text"}]},{"type":"paragraph","content":[{"text":"You have ","type":"text"},{"text":"this skill folder only","type":"text","marks":[{"type":"strong"}]},{"text":" — no K2F source checkout, no ","type":"text"},{"text":"templates/","type":"text","marks":[{"type":"code_inline"}]},{"text":" tree.","type":"text"}]},{"type":"paragraph","content":[{"text":"Install published tools before running workflows:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"pip install k2f # CLI on PATH + Python SDK — no need to install Cargo\nnpm i @openk2f/k2f # only when embedding \u003ck2f-viewer> in a web app\n# cargo install k2f # optional: CLI without Python","type":"text"}]},{"type":"paragraph","content":[{"text":"Run scripts from this skill directory (or pass absolute paths to them). Core scripts (","type":"text"},{"text":"init_package.py","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pack_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"modifier_range.py","type":"text","marks":[{"type":"code_inline"}]},{"text":") are ","type":"text"},{"text":"stdlib-only","type":"text","marks":[{"type":"strong"}]},{"text":" — ","type":"text"},{"text":"python scripts/…","type":"text","marks":[{"type":"code_inline"}]},{"text":". Optional ","type":"text"},{"text":"compare_images.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" needs ","type":"text"},{"text":"uv run","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"visual check","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing.md#reference-image-overlay-optional","title":null}}]},{"text":"). The author directory may live anywhere. ","type":"text"},{"text":"pack_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" needs ","type":"text"},{"text":"k2f","type":"text","marks":[{"type":"code_inline"}]},{"text":" on PATH (","type":"text"},{"text":"pip install k2f","type":"text","marks":[{"type":"code_inline"}]},{"text":") or ","type":"text"},{"text":"K2F_CLI","type":"text","marks":[{"type":"code_inline"}]},{"text":" — it does not walk a git checkout or build directory for a binary.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core rules","type":"text"}]},{"type":"paragraph","content":[{"text":"Empty paper in the ","type":"text"},{"text":"lower third","type":"text","marks":[{"type":"strong"}]},{"text":" of a designed sheet is the most common visual failure. ","type":"text"},{"text":"pack_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" exit 0 / ","type":"text"},{"text":"pages=1","type":"text","marks":[{"type":"code_inline"}]},{"text":" does ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" mean filled — open the PNG. Fix: copy ","type":"text"},{"text":"ex_filled_page.json","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/content/ex_filled_page.json","title":null}},{"type":"code_inline"}]},{"text":" as a ","type":"text"},{"text":"root child","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"height","type":"text","marks":[{"type":"code_inline"}]},{"text":" = content box; leftover on ","type":"text"},{"text":"{fr:1}","type":"text","marks":[{"type":"code_inline"}]},{"text":" table/notes/figure). Short letter and the last page of a growing document may stay short.","type":"text"}]},{"type":"paragraph","content":[{"text":"source/","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" edits are invisible until compile.","type":"text","marks":[{"type":"strong"}]},{"text":" Viewers paint ","type":"text"},{"text":"document.K2F.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":", not author JSON. After content/theme edits, run ","type":"text"},{"text":"pack_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":", then ","type":"text"},{"text":"tmp/preview.png","type":"text","marks":[{"type":"code_inline"}]},{"text":" or reload the ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Style lives only in ","type":"text","marks":[{"type":"strong"}]},{"text":"theme.json","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":", never on a node.","type":"text","marks":[{"type":"strong"}]},{"text":" Putting a style field on a node is the single most common compile failure.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Never hand-edit ","type":"text","marks":[{"type":"strong"}]},{"text":"document.K2F.lock","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":".","type":"text","marks":[{"type":"strong"}]},{"text":" Mutate the tree (or theme), then ","type":"text"},{"text":"pack_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" (relock).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PDF, PPTX, DOCX, and IDML are one-way drawings of the lock, not a second source.","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"PDF_IS_NOT_A_SOURCE","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"PPTX_IS_NOT_A_SOURCE","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"DOCX_IS_NOT_A_SOURCE","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"IDML_IS_NOT_A_SOURCE","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Signing is a separate human/org step.","type":"text","marks":[{"type":"strong"}]},{"text":" Agent output is ","type":"text"},{"text":"UNSIGNED","type":"text","marks":[{"type":"code_inline"}]},{"text":" by design.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validate after every edit.","type":"text","marks":[{"type":"strong"}]},{"text":" Fix from error codes in ","type":"text"},{"text":"writing/errors.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing/errors.md","title":null}}]},{"text":"; do not patch the lock.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Look at the pixels — empty bottom first.","type":"text","marks":[{"type":"strong"}]},{"text":" After pack, open every rendered page (","type":"text"},{"text":"--render","type":"text","marks":[{"type":"code_inline"}]},{"text":" writes ","type":"text"},{"text":"preview-1.png","type":"text","marks":[{"type":"code_inline"}]},{"text":" …). If the lower third is blank paper on a designed sheet, you are not done. ","type":"text"},{"text":"Designed sheet","type":"text","marks":[{"type":"strong"}]},{"text":" (invoice, CV, flyer, poster, slide, card, social, one-page infographic/checklist/planner — even if titled report) → copy ","type":"text"},{"text":"ex_filled_page.json","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/content/ex_filled_page.json","title":null}},{"type":"code_inline"}]},{"text":" as a ","type":"text"},{"text":"root child","type":"text","marks":[{"type":"strong"}]},{"text":" (pinned ","type":"text"},{"text":"height","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"{fr:1}","type":"text","marks":[{"type":"code_inline"}]},{"text":" grower); a ","type":"text"},{"text":"page_shell","type":"text","marks":[{"type":"code_inline"}]},{"text":" role on a hug stack is not the shell. Treat ","type":"text"},{"text":"PAGE_UNDERFILL","type":"text","marks":[{"type":"code_inline"}]},{"text":" as must-fix even when ","type":"text"},{"text":"pack_verify.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" exits 0 (skipped if the content box is shorter than 180pt). Short letter may stay top-packed. ","type":"text"},{"text":"Growing document","type":"text","marks":[{"type":"strong"}]},{"text":" (contract, long report, thesis, paper) → one flow tree; last page may be short; no ","type":"text"},{"text":"p1","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"p2","type":"text","marks":[{"type":"code_inline"}]},{"text":" page wrappers and no page-height shell around the whole doc. ","type":"text"},{"text":"break_before: page","type":"text","marks":[{"type":"code_inline"}]},{"text":" is fine on a chapter, annex, signature page, slide 2+, or card back. Details: ","type":"text"},{"text":"writing.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing.md#visual-check","title":null}}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Content and design","type":"text"}]},{"type":"paragraph","content":[{"text":"Before editing ","type":"text"},{"text":"content/","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"styles/theme.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", write content and design as Markdown ","type":"text"},{"text":"inside","type":"text","marks":[{"type":"strong"}]},{"text":" the author directory. Long content does not go in one file. Split the same way as ","type":"text"},{"text":"content/*.json","type":"text","marks":[{"type":"code_inline"}]},{"text":". Name each file with a ","type":"text"},{"text":"slug","type":"text","marks":[{"type":"strong"}]},{"text":": lowercase ASCII ","type":"text"},{"text":"kebab-case","type":"text","marks":[{"type":"code_inline"}]},{"text":" from that page or section’s topic (e.g. ","type":"text"},{"text":"executive-summary","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"title-slide","type":"text","marks":[{"type":"code_inline"}]},{"text":"). A short single page may be one ","type":"text"},{"text":"content_and_design.md","type":"text","marks":[{"type":"code_inline"}]},{"text":". One page per file → ","type":"text"},{"text":"content_and_design_\u003cslug>.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" (e.g. ","type":"text"},{"text":"content_and_design_agenda.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for a slide). Section aligned with a JSON fragment → ","type":"text"},{"text":"content_and_design_\u003cslug>.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" beside ","type":"text"},{"text":"content/\u003cslug>.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" using the ","type":"text"},{"text":"same","type":"text","marks":[{"type":"strong"}]},{"text":" slug. Then ","type":"text"},{"text":"python scripts/init_package.py --workspace ./out/doc …","type":"text","marks":[{"type":"code_inline"}]},{"text":" (creates ","type":"text"},{"text":"source/","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"tmp/","type":"text","marks":[{"type":"code_inline"}]},{"text":"; a notes-only ","type":"text"},{"text":"source/","type":"text","marks":[{"type":"code_inline"}]},{"text":" that already holds these files can still be initialized in place).","type":"text"}]},{"type":"paragraph","content":[{"text":"Workspace layout:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"./out/doc/\n doc.K2F # deliverable\n doc.pdf # optional exports, same stem\n source/ # author package (edit this)\n content_and_design_executive-summary.md\n manifest.json\n content/\n root.json\n executive-summary.json # optional fragment; same slug as its .md\n styles/ assets/ changelog.json\n tmp/ # preview.png and other debug renders","type":"text"}]},{"type":"paragraph","content":[{"text":"Each file covers that page or section only, and includes both:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Content","type":"text","marks":[{"type":"strong"}]},{"text":" — every word, and every image (what it shows, width×height; a full generation prompt when the image must be made). Need figures → ","type":"text"},{"text":"generate them","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing.md#figures","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Design","type":"text","marks":[{"type":"strong"}]},{"text":" — type hierarchy, spacing, color, and layout","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Shared type, color, and spacing for the whole document go in the first file. Later files state their own words and images, which shared set they use, and anything that differs.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User gave constraints","type":"text","marks":[{"type":"strong"}]},{"text":" — follow them.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User did not specify","type":"text","marks":[{"type":"strong"}]},{"text":" — highest aesthetic standard for the deliverable type (report, poster, slide deck, flyer, …). Do not ship the starter theme unchanged for styled work.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"After the files are settled: look up allowed keys in ","type":"text"},{"text":"writing/fields.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing/fields.md","title":null}}]},{"text":" then ","type":"text"},{"text":"schema/","type":"text","marks":[{"type":"link","attrs":{"href":"schema/","title":null}},{"type":"code_inline"}]},{"text":", implement ","type":"text"},{"text":"theme.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"content/","type":"text","marks":[{"type":"code_inline"}]},{"text":", run ","type":"text"},{"text":"pack_verify.py --render","type":"text","marks":[{"type":"code_inline"}]},{"text":", open the PNG, and iterate until the output matches these files. Rule 6 is the final gate — the files are the plan, render is the review.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Schema","type":"text"}]},{"type":"paragraph","content":[{"text":"Read-only format JSON Schemas live in ","type":"text"},{"text":"schema/","type":"text","marks":[{"type":"link","attrs":{"href":"schema/","title":null}},{"type":"code_inline"}]},{"text":" (same bytes the engine embeds). ","type":"text"},{"text":"Do not","type":"text","marks":[{"type":"strong"}]},{"text":" copy them into an author directory — ","type":"text"},{"text":"k2f pack","type":"text","marks":[{"type":"code_inline"}]},{"text":" injects schemas into the ZIP; hand-authored ","type":"text"},{"text":"schema/","type":"text","marks":[{"type":"code_inline"}]},{"text":" files → ","type":"text"},{"text":"UNEXPECTED_PATH","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Allowed keys:","type":"text","marks":[{"type":"strong"}]},{"text":" skim ","type":"text"},{"text":"writing/fields.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing/fields.md","title":null}}]},{"text":", then open only the schema file you are editing — ","type":"text"},{"text":"content/","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"schema/nodes.schema.json","type":"text","marks":[{"type":"link","attrs":{"href":"schema/nodes.schema.json","title":null}},{"type":"code_inline"}]},{"text":"; ","type":"text"},{"text":"styles/theme.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"schema/styles.schema.json","type":"text","marks":[{"type":"link","attrs":{"href":"schema/styles.schema.json","title":null}},{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"schema/visual_primitives.schema.json","type":"text","marks":[{"type":"link","attrs":{"href":"schema/visual_primitives.schema.json","title":null}},{"type":"code_inline"}]},{"text":"; ","type":"text"},{"text":"manifest.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"schema/manifest.schema.json","type":"text","marks":[{"type":"link","attrs":{"href":"schema/manifest.schema.json","title":null}},{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"First draft shapes:","type":"text","marks":[{"type":"strong"}]},{"text":" copy from ","type":"text"},{"text":"catalog/content/ex_*.json","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/content/","title":null}},{"type":"code_inline"}]},{"text":" into root ","type":"text"},{"text":"children","type":"text","marks":[{"type":"code_inline"}]},{"text":" — golden, packable examples. See ","type":"text"},{"text":"catalog/README.md","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/README.md","title":null}},{"type":"code_inline"}]},{"text":" for a construct index.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"SCHEMA_INVALID","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":":","type":"text","marks":[{"type":"strong"}]},{"text":" compare the failing object to the schema file. Key ","type":"text"},{"text":"in","type":"text","marks":[{"type":"strong"}]},{"text":" schema but rejected → stale CLI (","type":"text"},{"text":"pip install -U k2f","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Key ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" in schema → remove it; do not invent fields from HTML/CSS memory.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Version check:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"k2f schema dump -o /tmp/k2f-schema","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"python -c \"import k2f; print(k2f.format_schemas().keys())\"","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Bundled packages","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Path","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"schema/","type":"text","marks":[{"type":"link","attrs":{"href":"schema/","title":null}},{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Read-only format JSON Schemas — lookup after ","type":"text"},{"text":"writing/fields.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/writing/fields.md","title":null}}]},{"text":"; never copy into author dirs","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"starter/","type":"text","marks":[{"type":"link","attrs":{"href":"starter/","title":null}},{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Empty tree + core theme + Roboto — copied into ","type":"text"},{"text":"source/","type":"text","marks":[{"type":"code_inline"}]},{"text":" when there is no existing ","type":"text"},{"text":".K2F","type":"text","marks":[{"type":"code_inline"}]},{"text":" and no matching Gallery package","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"catalog/","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/","title":null}},{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Golden shape dictionary — copy ","type":"text"},{"text":"ex_*.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" nodes into the author dir; not a deliverable (","type":"text"},{"text":"index","type":"text","marks":[{"type":"link","attrs":{"href":"catalog/README.md","title":null}}]},{"text":")","type":"text"}]}]}]}]}]},"metadata":{"date":"2026-11-02","name":"k2f","author":"@skillopedia","source":{"stars":4,"repo_name":"k2f","origin_url":"https://github.com/suzheng/k2f/blob/HEAD/skills/core/k2f/SKILL.md","repo_owner":"suzheng","body_sha256":"6f5dbad6da0d017d2409131d57724d9501288f703d6a3351d1a8816a47abe416","cluster_key":"ca42f4df677ba74aef26a4811b450a1bafbe279c4afd710687aea95ac9a3bf0b","clean_bundle":{"format":"clean-skill-bundle-v1","source":"suzheng/k2f/skills/core/k2f/SKILL.md","text_bytes":318409,"source_commit":"f49dd3fa43b93dacf604aa016f3e50faa20b1984","skills_sh_rank":5250,"attachment_count":71,"text_attachments":71,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/core/k2f/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"documents-office","category_label":"Documents"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"documents-office","import_tag":"skills-sh-top20k-2026-11","description":"Create, design, edit, validate, and export elegant Word (docx), editable PDF, fillable AcroForm PDF, and Adobe InDesign (IDML) documents with K2F. Use when creating aesthetic Word, fillable PDF, AcroForm, IDML, or InDesign documents with AI agents, such as menus, certificates, planners, invitations, or worksheets and much more. K2F is a mature file format designed for AI agents to design and edit elegant aesthetic documents precisely and effortlessly. It has a rich ecosystem."}},"renderedAt":1793666032822}

K2F Create, design, edit elegant Word (docx), PDF, fillable AcroForm PDF, and Adobe InDesign (IDML) with K2F. K2F designed for agents to design and edit elegant documents precisely and effortlessly. Use with AI agents when you need aesthetic documents—menus, certificates, planners, invitations, worksheets, and more. You can start from Gallery templates. A is a ZIP: you edit a semantic JSON tree (meaning, not coordinates); the engine / s an immutable render lock. One reference engine → pixel-identical output everywhere. Choose the workflow Read one reference file for the task. Do not load all…