Add a supported host-font configuration for bundled LibreOffice and Poppler runtimes

Open 💬 2 comments Opened Jul 14, 2026 by biaobiaobiao108

What is the type of issue?

Feature request / bug

What is the issue?

The bundled primary runtime on macOS does not provide a supported way to expose the host system font directories to bundled fontconfig-based tools such as LibreOffice and Poppler.

In a macOS Codex Desktop runtime, the bundled LibreOffice can convert a PPTX to PDF, but Simplified Chinese text may disappear when soffice is launched without an explicit FONTCONFIG_FILE environment variable.

The runtime contains its own Fontconfig configuration and fonts, but the bundled Fontconfig library is compiled with an internal install-time path similar to:

/@.__________________________________________________OOO/etc/fonts

The runtime sandbox does not expose a normal /etc/fonts directory, and LibreOffice does not automatically load the configuration shipped under its application resources:

LibreOfficeDev.app/Contents/Resources/fontconfig/fonts.conf

As a result, editing that bundled fonts.conf alone is insufficient for a bare soffice invocation.

Reproduction

Environment:

OS: macOS arm64
Codex Desktop primary runtime bundle: 26.709.11516
LibreOfficeDev: 26.8.0.0.alpha0

The runtime provides a bundled soffice and Poppler. With the host system font directories not explicitly configured:

unset FONTCONFIG_FILE FONTCONFIG_PATH
soffice --headless --convert-to pdf input.pptx --outdir /tmp/output

Fontconfig emits warnings such as:

Fontconfig warning: no <cachedir> elements found
Fontconfig warning: adding <cachedir>/@.__________________________________________________OOO/var/cache/fontconfig

A PPTX containing Simplified Chinese text converts to PDF, but the Chinese glyphs are missing or blank. pdffonts shows only the bundled Latin fonts, for example LinuxLibertineG.

By contrast, explicitly pointing Fontconfig at a configuration that includes the host directories makes the same conversion work:

export FONTCONFIG_FILE=/path/to/runtime/config/fontconfig/fonts.conf
export FONTCONFIG_PATH=/path/to/runtime/config/fontconfig
soffice --headless --convert-to pdf input.pptx --outdir /tmp/output

The working configuration references:

/System/Library/Fonts
/System/Library/Assets
/System/Library/AssetsV2
/Library/Fonts
~/Library/Fonts

The resulting PDF embeds PingFangSC-Regular, and the rendered Chinese text is visible.

Expected behavior

The primary runtime should provide a supported runtime-level font configuration mechanism so all bundled renderers can read host fonts without per-command workarounds.

Possible designs:

  • A runtime configuration option for read-only host font directories.
  • A documented FONTCONFIG_FILE / FONTCONFIG_PATH environment hook applied to all runtime child processes.
  • A runtime launcher that mounts or exposes host font directories read-only and points Fontconfig at a runtime-owned configuration.
  • A documented setting for selecting a curated system font root without copying fonts into the runtime.

The configuration should cover at least:

  • LibreOffice / soffice
  • Poppler tools such as pdftoppm and pdftocairo
  • Other bundled renderers that use Fontconfig

Why this matters

Users should not need to:

  • Copy PingFang or other system fonts into the runtime.
  • Modify cached runtime files after every Codex upgrade.
  • Create command-specific wrappers.
  • Guess or patch the internal /@.../etc/fonts install path.
  • Accept missing CJK text in generated PDFs.

A read-only host font directory exposure would avoid duplicated font files and would be low risk compared with exposing broader host filesystem paths.

Related issue

This is related to #28889, which discusses Fontconfig cache handling for Poppler in sandboxed workspaces, but this report is specifically about the missing supported host-font configuration and the resulting CJK rendering failure in bundled LibreOffice/Poppler.

Additional information

A local workaround is to set FONTCONFIG_FILE and FONTCONFIG_PATH in the runtime launch environment and use a configuration that points to the macOS system font directories. This works, but the runtime currently has no documented global hook for doing so, and modifying files under ~/.cache/codex-runtimes is vulnerable to runtime replacement during upgrades.

View original on GitHub ↗

2 Comments

ksmkzs · 1 month ago

Additional evidence from the bundled Documents/DOCX workflow on macOS (primary runtime and Documents plugin 26.715.12143):

I reproduced the same root cause with three generated, non-embedded DOCX probes:

| Requested family | Existing source on the host | Packaged render_docx.py |
|---|---|---|
| Noto Sans JP | user font directory | requested family absent from pdffonts |
| MS Mincho | Microsoft Word DFonts | requested family absent |
| Aptos Display | Office FontCache/CloudFonts | requested family absent |

The packaged renderer produced PDFs in all three cases, so output-file existence was a false-positive success signal. All three PDFs instead contained only runtime/fallback families such as Linux Libertine G, DejaVu Sans, and Noto Sans.

Using an external FONTCONFIG_FILE with absolute, read-only font directory paths made the same three probes resolve exactly by family. pdffonts then reported NotoSansJP-Regular, MS-Mincho, and AptosDisplay respectively; Japanese text was visible in the rendered PNG and recoverable with pdftotext.

This confirms the issue affects the Documents plugin's DOCX→PDF→PNG review path, not only PPTX conversion. Embedded fonts are a separate package path and do not solve ordinary non-embedded documents.

Suggested acceptance coverage for an upstream fix:

  1. Capture the real account home before creating the isolated LibreOffice HOME.
  2. Generate or select a runtime-owned Fontconfig config/cache with explicit supported host directories.
  3. Test a generated non-embedded DOCX and assert the requested family in pdffonts; do not treat PDF/PNG existence alone as success.
  4. Define policy separately for app-private and Office-cached fonts (possibly opt-in). This experiment proves technical discoverability, not license entitlement.
  5. Keep the fix runtime-level so Documents, Presentations, and Poppler-based workflows share the same supported mechanism.

A local cache reconciler can mitigate runtime refreshes, but it is not a good upstream substitute. The public repository also does not currently contain the primary-runtime Documents source, and external PRs are invitation-only, so I am adding the reproducible evidence here rather than opening a speculative PR.

Hao-Wu · 18 hours ago

I reproduced this issue on macOS and confirmed that explicitly configuring Fontconfig fixes DOCX/PDF rendering with CJK fonts.

Environment:

  • Codex primary runtime bundle: 26.826.12353
  • Bundled LibreOfficeDev: 26.8.0.0.alpha0
  • System LibreOffice: 26.2.5.2
  • macOS arm64

The soffice found in the Codex runtime is a wrapper around:

~/.cache/codex-runtimes/codex-primary-runtime/dependencies/native/
libreoffice-headless/libreoffice/LibreOfficeDev.app/Contents/MacOS/soffice

Without an explicit Fontconfig configuration, a DOCX containing PingFang SC, Songti SC, SimSun, SimHei, KaiTi, Microsoft YaHei, and DengXian rendered every Chinese character as a missing-glyph box. pdffonts showed only bundled Latin fonts such as LinuxLibertineG.

Minimal fix

The bundled LibreOffice resources already contain a usable Fontconfig configuration. Explicitly exporting these variables before running the Codex renderer fixes system-font discovery:

RUNTIME_ROOT="$HOME/.cache/codex-runtimes/codex-primary-runtime"
LO_RESOURCES="$RUNTIME_ROOT/dependencies/native/libreoffice-headless/libreoffice/LibreOfficeDev.app/Contents/Resources"

export FONTCONFIG_FILE="$LO_RESOURCES/fontconfig/fonts.conf"
export FONTCONFIG_PATH="$LO_RESOURCES/fontconfig"

python render_docx.py input.docx --output_dir output --emit_pdf

After this change, PingFang and Songti rendered correctly.

Additional issue with user-installed fonts

The Codex render_docx.py helper creates an isolated LibreOffice profile and temporarily changes HOME to that profile. Consequently, this entry in the bundled fonts.conf:

<dir>~/Library/Fonts</dir>

no longer refers to the real macOS user font directory.

To support fonts installed under the actual user account, I created a persistent Fontconfig file at:

~/.codex/fontconfig/codex-lo-fonts.conf

The relevant configuration is:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
  <dir>/Users/USERNAME/.cache/codex-runtimes/codex-primary-runtime/dependencies/native/libreoffice-headless/libreoffice/LibreOfficeDev.app/Contents/Resources/fonts/truetype</dir>

  <dir>/System/Library/Fonts</dir>
  <dir>/System/Library/Fonts/Supplemental</dir>
  <dir>/System/Library/AssetsV2</dir>
  <dir>/Library/Fonts</dir>

  <!-- Must be absolute because render_docx.py replaces HOME -->
  <dir>/Users/USERNAME/Library/Fonts</dir>

  <!-- Optional: read fonts from an existing Word installation without
       launching Word or copying its font files -->
  <dir>/Applications/Microsoft Word.app/Contents/Resources/DFonts</dir>

  <include ignore_missing="yes">/Users/USERNAME/.cache/codex-runtimes/codex-primary-runtime/dependencies/native/libreoffice-headless/libreoffice/LibreOfficeDev.app/Contents/Resources/fontconfig/conf.d</include>

  <include ignore_missing="yes">/Users/USERNAME/.cache/codex-runtimes/codex-primary-runtime/dependencies/native/libreoffice-headless/libreoffice/LibreOfficeDev.app/Contents/Resources/fonts/truetype/fc_local.conf</include>

  <cachedir prefix="xdg">fontconfig</cachedir>

  <config>
    <rescan>
      <int>30</int>
    </rescan>
  </config>
</fontconfig>

Replace USERNAME with the actual macOS account name.

Persistent rendering wrapper

I installed a wrapper at:

~/.codex/bin/render-docx-cjk

It exports the Fontconfig variables before invoking the current Codex document renderer:

#!/usr/bin/env bash
set -euo pipefail

CODEX_RUNTIME="/Users/USERNAME/.cache/codex-runtimes/codex-primary-runtime"
LO_RESOURCES="$CODEX_RUNTIME/dependencies/native/libreoffice-headless/libreoffice/LibreOfficeDev.app/Contents/Resources"

export FONTCONFIG_FILE="/Users/USERNAME/.codex/fontconfig/codex-lo-fonts.conf"
export FONTCONFIG_PATH="$LO_RESOURCES/fontconfig"

PYTHON_BIN="$CODEX_RUNTIME/dependencies/python/bin/python3"

shopt -s nullglob
RENDERERS=(/Users/USERNAME/.codex/plugins/cache/openai-primary-runtime/documents/*/skills/documents/render_docx.py)

if (( ${#RENDERERS[@]} == 0 )); then
  echo "Codex document renderer was not found." >&2
  exit 1
fi

RENDERER="${RENDERERS[${#RENDERERS[@]}-1]}"
exec "$PYTHON_BIN" "$RENDERER" "$@"

Making Codex use the workaround automatically

The wrapper alone does not guarantee that future Codex tasks will use it. An agent may still invoke render_docx.py or bare soffice directly, or try to automate Microsoft Word.

To make the behavior persistent across projects, I also added global instructions to:

~/.codex/AGENTS.md

The relevant instructions are:

## Unattended Word document preview

- When reading, creating, or editing DOCX files, use the document skill's
  LibreOffice render-to-PNG visual QA workflow.
- On this Mac, always invoke `/Users/USERNAME/.codex/bin/render-docx-cjk`
  instead of calling `render_docx.py` or bare `soffice` directly.
- Do not launch Microsoft Word, AppleScript, or GUI automation for automatic
  previews. Use Word only when the user explicitly requests it.
- If a rendered page contains missing-glyph boxes, blank text, or obvious font
  substitution, verify that `FONTCONFIG_FILE` points to
  `/Users/USERNAME/.codex/fontconfig/codex-lo-fonts.conf`, fix font discovery,
  and render again.
- Do not treat a page with missing glyphs as having passed visual QA.

Codex reads ~/.codex/AGENTS.md as global guidance at the start of future tasks. This turns the environment-variable workaround into the default document-rendering behavior instead of relying on the user to remind each agent.

Verification

Using the persistent configuration and wrapper, the generated PDF contained these embedded fonts:

PingFangSC-Regular
PingFangSC-Semibold
STSongti-SC-Regular
SimSun
SimHei
KaiTi_GB2312
MicrosoftYaHei
DengXian-Regular

The rendered PNG contained complete Chinese text, with visible differences between the requested font families and no missing-glyph boxes.

This workaround:

  • does not modify files under the replaceable runtime cache;
  • does not copy macOS or Microsoft fonts;
  • does not launch Microsoft Word;
  • works with the normal Codex render-and-inspect workflow;
  • can be selected automatically in future tasks through global AGENTS.md guidance;
  • remains usable across runtime updates as long as the primary runtime directory structure remains stable.

The ideal upstream fix would be for the bundled soffice launcher or render_docx.py to set FONTCONFIG_FILE and FONTCONFIG_PATH automatically. On macOS, the configuration should include /System/Library/AssetsV2 and preserve access to the real user font directory even when HOME is replaced with an isolated LibreOffice profile.