Skip to content

[BUG] Failures when reading/writing .copilot_instructions on Windows #1126

Description

@matelich

Description

Trying to run headroom wrap for the first time on one of my projects, it crashed with UnicodeDecodeError due to typographic quotes - “happy places”.

To Reproduce

Steps to reproduce the behavior:

  1. Install headroom 0.26.0 on Windows with pip
  2. From pwsh, in a repo with a utf-8 formatted .copilot_instructions containing multi-byte characters, run headroom wrap copilot --subscription -- --model gpt-5.4
  3. See error

Expected Behavior

At this moment, I've edited _inject_rtk_instructions in cli/wrap.py to pass encoding="utf-8" to read_text and write. I'm not sure if this is the best solution, overall.

Actual Behavior

Crash

Code Sample

def _inject_rtk_instructions(file_path: Path, verbose: bool = False) -> bool:
    """Inject rtk instructions into a file (AGENTS.md, .cursorrules, etc.).

    Idempotent — skips if marker already present. Appends to existing content.
    Returns True if instructions were written.
    """
    if file_path.exists():
        click.echo(f"  check for rtk instructions in {file_path.name}")
        existing = file_path.read_text(encoding="utf-8")
        if _RTK_MARKER in existing:
            if verbose:
                click.echo(f"  rtk instructions already in {file_path.name}")
            return True
        # Append to existing file
        with open(file_path, "a", encoding="utf-8") as f:
            f.write("\n\n" + RTK_INSTRUCTIONS_BLOCK)
    else:
        file_path.parent.mkdir(parents=True, exist_ok=True)
        file_path.write_text(RTK_INSTRUCTIONS_BLOCK, encoding="utf-8") # untested

    click.echo(f"  rtk instructions injected into {file_path}")
    return True

Error Output

PS D:\dev\robots> headroom wrap copilot --subscription -- --model gpt-5.4
  Setting up rtk for Copilot...
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Scripts\headroom.exe\__main__.py", line 5, in <module>
    sys.exit(main())
             ~~~~^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1524, in __call__
    return self.main(*args, **kwargs)
           ~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1445, in main
    rv = self.invoke(ctx)
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1912, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1912, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1308, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 877, in invoke
    return callback(*args, **kwargs)
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\headroom\cli\wrap.py", line 3217, in copilot
    _inject_rtk_instructions(copilot_instructions, verbose=verbose)
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\headroom\cli\wrap.py", line 1487, in _inject_rtk_instructions
    existing = file_path.read_text()
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\pathlib\_local.py", line 546, in read_text
    return PathBase.read_text(self, encoding, errors, newline)
           ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\pathlib\_abc.py", line 633, in read_text
    return f.read()
           ~~~~~~^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\encodings\cp1252.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 4376: character maps to <undefined>

After fixing the injection and restarting, I also got this error:

PS D:\dev\robots> headroom wrap copilot --subscription -- --model gpt-5.4
  Setting up rtk for Copilot...
  check for rtk instructions in copilot-instructions.md
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Scripts\headroom.exe\__main__.py", line 5, in <module>
    sys.exit(main())
             ~~~~^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1524, in __call__
    return self.main(*args, **kwargs)
           ~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1445, in main
    rv = self.invoke(ctx)
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1912, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1912, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 1308, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\click\core.py", line 877, in invoke
    return callback(*args, **kwargs)
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\headroom\cli\wrap.py", line 3218, in copilot
    _inject_rtk_instructions(copilot_instructions, verbose=verbose)
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\site-packages\headroom\cli\wrap.py", line 1488, in _inject_rtk_instructions
    existing = file_path.read_text(encoding="utf-8")
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\pathlib\_local.py", line 546, in read_text
    return PathBase.read_text(self, encoding, errors, newline)
           ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\tomm\AppData\Local\Programs\Python\Python313\Lib\pathlib\_abc.py", line 633, in read_text
    return f.read()
           ~~~~~~^^
  File "<frozen codecs>", line 325, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x97 in position 6569: invalid start byte

Which is why I changed the call to write

Environment

  • Headroom version: 0.26.0
  • Python version: 3.13.7
  • OS: Windows 11
  • LLM Provider: Copilot

Additional Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions