Skip to main content
Patch follow-up to beta.13. SessionStart hooks now emit a one-shot <first-reply-notice> so the first visible assistant reply confirms Trellis context has been injected. READY-state breadcrumbs were rewritten to explicitly require trellis-implement dispatch on agent-capable platforms, closing a loophole where the main thread would hand-edit code itself. Claude Code’s statusline now survives the Windows UTF-8 encoding setup on Python builds that ship typed stdio.

Enhancements

One-shot SessionStart announcement on the first reply

Users had no clear signal that Trellis’s SessionStart hook had actually injected. SessionStart hooks now prepend the following block to additionalContext:
<first-reply-notice>
On the first visible assistant reply in this session, begin with exactly one short Chinese sentence:
Trellis SessionStart 已注入:workflow、当前任务状态、开发者身份、git 状态、active tasks、spec 索引已加载。
Then continue directly with the user's request. This notice is one-shot: do not repeat it after the first assistant reply in the same session.
</first-reply-notice>
Applied to:
  • packages/cli/src/templates/shared-hooks/session-start.py
  • packages/cli/src/templates/codex/hooks/session-start.py
  • packages/cli/src/templates/opencode/plugins/session-start.js
copilot/hooks/session-start.py keeps the JSON shape for protocol parity but omits the notice because GitHub Copilot currently ignores sessionStart output (see Docs below).

READY-state Next-Action copy rewritten

The old breadcrumb copy was:
Status: READY
Task: <title>
Next: Continue with implement or check
On agent-capable platforms this prompt could let the main agent process write code itself, bypassing the sub-agent workflow. New copy:
Status: READY
Task: <title>
Next required action: dispatch `trellis-implement` per Phase 2.1.
For agent-capable platforms, do NOT edit code in the main session.
After implementation, dispatch `trellis-check` per Phase 2.2 before reporting completion.
The <ready> closing directive also changed from “If there is an active task, ask whether to continue it” to “If a task is READY, execute its Next required action without asking whether to continue.” Uniformly applied across:
FileScope
shared-hooks/session-start.pyClaude Code, Gemini, Qoder, Kiro, iFlow
shared-hooks/inject-workflow-state.pyUserPromptSubmit fallback breadcrumb
opencode/plugins/session-start.jsOpenCode SessionStart
opencode/plugins/inject-workflow-state.jsOpenCode fallback breadcrumb
codex/hooks/session-start.pyCodex SessionStart
copilot/hooks/session-start.pyCopilot (hook present, see Docs)
trellis/workflow.md[workflow-state:in_progress] block

Bug Fixes

Claude Code statusline: Windows UTF-8 encoding setup no longer crashes

Claude Code’s statusline (.claude/hooks/statusline.py, sourced from shared-hooks/statusline.py) needs to flip stdout/stderr to UTF-8 on Windows — otherwise glyphs like the middle dot (·) get mangled by GBK. The old setup was:
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding="utf-8")
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding="utf-8")
On some Windows Python builds, sys.stdout / sys.stderr are typed wrappers that do not expose detach(). Calling it raised, the statusline process died, and Claude Code’s top info line went blank. The fix uses the standard io.TextIOBase.reconfigure() API (Python 3.7+) when available and no-ops otherwise:
if sys.platform == "win32":
    for stream in (sys.stdout, sys.stderr):
        reconfigure = getattr(stream, "reconfigure", None)
        if callable(reconfigure):
            reconfigure(encoding="utf-8", errors="replace")
reconfigure is standard on Python 3.7+ text streams; errors="replace" keeps rendering when the host refuses a rare glyph.

Codex & Copilot SessionStart reuse the project’s own encoding setup

Both hooks now run configure_project_encoding(project_dir) before emitting JSON: add .trellis/scripts/ to sys.path, call common.configure_encoding() if the project ships it, skip otherwise:
def configure_project_encoding(project_dir: Path) -> None:
    scripts_dir = project_dir / ".trellis" / "scripts"
    if str(scripts_dir) not in sys.path:
        sys.path.insert(0, str(scripts_dir))
    try:
        from common import configure_encoding  # type: ignore[import-not-found]
        configure_encoding()
    except Exception:
        pass
Prevents mojibake in hook stdout on Windows Codex/Copilot runs that have not already wrapped stdout.

Docs

Copilot sessionStart hook is currently advisory

copilot/hooks/session-start.py’s module docstring and systemMessage now state explicitly that GitHub Copilot’s documented SessionStart behavior ignores hook stdout. The script continues to emit the Trellis payload (for parity with other hosts and eventual Copilot support), but the old success message — Trellis context injected (<n> chars) — was misleading on this host. It now reads Trellis SessionStart diagnostics emitted (<n> chars); Copilot currently ignores sessionStart hook output. Copilot users should rely on UserPromptSubmit breadcrumbs (which are honored) and hook logs to verify Trellis engagement, not SessionStart output.

Upgrade

Existing projects:
trellis update
No migration steps. Existing tasks, jsonl files, and .current-task are preserved. On the next session start you’ll see a one-line Chinese confirmation that Trellis context was injected, and READY tasks will push you to trellis-implement without the old “continue?” prompt. Claude Code’s statusline on Windows no longer crashes during UTF-8 encoding setup. Fresh install:
npm i -g @mindfoldhq/[email protected]