Theme: Agent self-awareness + safety + distribution polish.
Authored: 2026-05-18 (post v2.4.0 ship + dreamrec/TDPilot v1.6.16 upstream audit).
Status: SHIPPED 2026-05-19 as v2.5.0 → v2.5.4. See docs/plans/README.md v2.5 retrospective, the post-2.5.3 audit retrospective, and the v2.5.4 hardening retrospective for the as-shipped scope (8 phases + 3 live-audit patches + 1 hardening release). This plan file is preserved as the historical pre-ship blueprint; phase statuses below are marked SHIPPED for archival accuracy but do not edit further.
For the receiving agent: Drop this file into a fresh Claude Code session inside the TDPilot DPSK4 repo and say "execute v2.5". Everything below is self-contained — no prior session memory required. Each phase has a unique
id, astatusfield, pre-flight checks, validation gates, and resume instructions. Edit thestatusfield as you complete phases so the next session knows where to start.
- Latest shipped: v2.4.0 (commits
41dbaaa+8f087cd+a105feaonmain, 2026-05-13). 105 MCP tools. 2000 tests passing. - Source of v2.5 themes:
docs/plans/v2.4_IMPLEMENTATION_PLAN.md+ upstreamdreamrec/TDPilotv1.6.16 (2026-05-18). - Branch: start a fresh branch off
main:git checkout -b claude/v2.5.0-dev. - Worktree: if continuing from
.claude/worktrees/<slug>/of a prior session, verifygit statusis clean before starting any phase.
Critical derived artifacts (per CLAUDE.md)
td_component/tdpilot-dpsk4.tox— rebuild in TD when any_TOX_SOURCE_FILESlisted inbuild_export_mcp_tox.pychanges.td_component/tdpilot_API.tox— rebuild in TD when any_API_TOX_SOURCE_FILESlisted inbuild_tdpilot_api_tox.pychanges.- Tool count —
EXPECTED_MIN_TOOL_COUNTinsrc/td_mcp/release_gates.py. Currently 105. v2.5 adds 5 new MCP tools → 110. Bump and update all user-facing copies (README.md, npm/README.md, plugin_README.md, docs/, skills/, CHANGELOG, marketplace.json description, npm/package.json description, GitHub repo description). - CHANGELOG.md — per-phase entries during dev; clean v2.5.0 entry on release.
- Seven version manifests —
pyproject.toml,src/td_mcp/__init__.py,.claude-plugin/plugin.json,.claude-plugin/marketplace.json,npm/package.json,mcp/manifest.json,td_component/mcp_webserver_callbacks.py::API_VERSION. Enforced byscripts/check_versions.py. tdpilot.plugin— rebuild viauv run python scripts/build_plugin_zip.pyat release time.- GitHub Release — after
git push origin v2.5.0, also rungh release create v2.5.0. Per feedback memory.
Same as v2.4: cost is not a constraint; maximize intelligence per turn. v2.5 layers ADDITIVE features — no breaking changes to existing chat-pipe sessions. All new features ship with feature-flags / Menu COMP params for opt-out.
Use tdpilot-dpsk4 (npm), ~/.tdpilot-dpsk4/api/ (config dir), ~/.tdpilot-dpsk4/.tdpilot-dpsk4.env (MCP env file). NEVER tdpilot-deepseek* or parent-fork tdpilot. Pinned by tests/test_release_critical_names.py.
| Phase ID | Item | Effort | Tox rebuild | Status |
|---|---|---|---|---|
v2.5.1-activity-log |
Activity log ring buffer + td_get_activity_log + _read_journal hints |
3 days | Both | SHIPPED v2.5.0 |
v2.5.2-ocr |
OCR sidecar on Phase B vision pipeline ([ocr] extras) |
4 days | MCP only | SHIPPED v2.5.0 (td_ocr_image) |
v2.5.3-tool-approval |
Approvalmode COMP param + runtime gate + chat UI |
3 days | API only | SHIPPED v2.5.0 |
v2.5.4-auth-fallback |
TD-side MCP auth fallback file (~/.tdpilot-dpsk4/.tdpilot-dpsk4.env enforcement) |
1 day | None | SHIPPED v2.5.0 (maybe_migrate_env_to_file) |
v2.5.5-td-release-card |
TD 2025.32820 release card markdown | 1 hour | None | SHIPPED (pre-v2.5) |
v2.5.6-npm-stdio |
npm wrapper stdout/stderr separation (Claude Desktop compat) | 1 day | None | SHIPPED v2.5.0 (stdio-discipline AST contract test) |
v2.5.7-check-updates |
td_check_for_updates read-only tool |
2 days | MCP only | SHIPPED v2.5.0 |
v2.5.8-log-receiver |
(Stretch) MCP-stderr tail to TD Table DAT | 2 days | API only | SHIPPED v2.5.0 (re-scoped to td_get_traces trace viewer) |
Total scope: 8 phases, ~16 days of work, ~3 calendar weeks with discipline.
Phase 1–4 are core; 5–7 are quick polish; 8 is stretch. If schedule slips, drop 8 first.
Subagent strategy: phases 4, 5, 6 (quick polish) are independent — dispatch in parallel via separate agent sessions when convenient. Phases 1, 2, 3 are sequential within their domain but independent across domains (1 = observability, 2 = vision, 3 = safety) so they CAN run in parallel agents.
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.1-activity-log
Tox rebuild: Both .tox files (chat-pipe needs ring; MCP needs tool)
The activity log produces the data; journal hints consume it. Splitting them creates a half-feature window where the log exists but nothing reads it. Ship together in a single PR.
git status # clean tree
git rev-parse --abbrev-ref HEAD # on claude/v2.5.1-activity-log or main
uv run python scripts/check_versions.py # baseline green
uv run pytest tests/ --ignore=tests/agent_evals -x -q # baseline ~2000 pass
grep EXPECTED_MIN_TOOL_COUNT src/td_mcp/release_gates.py # should be 105src/td_mcp/observability/__init__.py— module markersrc/td_mcp/observability/activity_log.py—ActivityRecorddataclass +ActivityRingclass (collections.deque(maxlen=200)-backed) + per-turn reset hooksrc/td_mcp/registry/observability_tools.py— registerstd_get_activity_logvia the existingtool_registrypattern (mirror thetd_fooexample at line ~683)tests/test_v25_activity_log.py— ring FIFO eviction, filter, since-tstests/test_v25_journal_hints.py— threshold logic, args_hash uses B-010 deep-canonical
src/td_mcp/tool_registry.py— appendActivityRecordon every dispatch in the wrapper. Wrap tool return values with_read_journalwhen(tool_name, args_hash)count ≥ 2 this turn.src/td_mcp/release_gates.py— bumpEXPECTED_MIN_TOOL_COUNT: int = 106td_component/tdpilot_api_runtime.py— chat-pipe variant of ring buffer + same journal-hint wrap on tool resultstd_component/tdpilot_api_runtime.py— refine B-007 protocol point 6 inSYSTEM_PROMPT_BASEto acknowledge journal hints (so the LLM sees both static guidance + runtime hint)td_component/build_tdpilot_api_tox.py::_API_TOX_SOURCE_FILES— verifytdpilot_api_runtime.pyalready in tuple (it is)CHANGELOG.md— Unreleased section, addv2.5.1-activity-logentrydocs/API_REFERENCE.md(or equivalent) — documenttd_get_activity_log
@dataclass(frozen=True, slots=True)
class ActivityRecord:
ts: float # time.monotonic()
tool_name: str
args_hash: str # reuse deep-canonical hash from B-010
duration_ms: int
result_kind: Literal["ok", "error", "no_change"]
error_msg: Optional[str] = None
# Tool result wrapper
{
"data": {...actual tool result...},
"_read_journal": {
"call_count": 3,
"state_unchanged": True,
"hint": "You've called td_get_errors with these exact args 3 times this turn with no change. Consider switching strategy — see protocol point 6."
}
}count == 2: low-friction nudge in hint textcount == 3: stronger reinforcement referencing protocol point 6 (B-007)count == 4: cycle-detect throws (existing B-010 behavior; unchanged)
@mcp.tool()
async def td_get_activity_log(
limit: int = 50,
tool_filter: Optional[str] = None,
since_ts: Optional[float] = None,
) -> dict:
"""Return recent agent tool-call activity (200-entry ring buffer)."""- 5 in
test_v25_activity_log.py: FIFO eviction at 201st entry, filter-by-tool, since-ts cutoff, result_kind classification, JSON-serializable - 8 in
test_v25_journal_hints.py: count=2 nudge, count=3 reinforcement, count=4 cycle-detect path unchanged, args_hash deep-canonical regression (list-order independence per B-010), per-turn ring reset, hint absent when count=1, hint format stable, chat-pipe variant matches MCP variant
grep "EXPECTED_MIN_TOOL_COUNT: int = 106" src/td_mcp/release_gates.py # bumped
uv run pytest tests/test_v25_activity_log.py tests/test_v25_journal_hints.py -v
uv run pytest tests/ --ignore=tests/agent_evals -x -q # no regressions; ~2013 pass
uv run python scripts/check_versions.py # only release_gates.py changed; versions still in sync
uv run python scripts/check_tox_freshness.py # would fail until user rebuilds .tox
uv run python scripts/check_tox_api_freshness.py # would fail until user rebuilds .tox- Risk: Ring buffer memory growth on long sessions. Mitigation:
deque(maxlen=200)caps; ActivityRecord usesslots=True. - Risk: Hash collision masking real loops. Mitigation: reuse B-010 deep-canonical (already collision-tested).
- Risk: Hint text bloats system prompt size. Mitigation: hints are in tool RESULT not system prompt; per-turn reset.
After this PR merges, mark v2.5.1-activity-log status as completed in this file's overview table. Next phase: v2.5.2-ocr (independent — can start in parallel).
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.2-ocr
Tox rebuild: MCP .tox only (vision pipeline lives MCP-side)
v2.4 Phase B injects screenshots into the LLM via Anthropic-compat vision blocks. Agent can SEE but can't reliably READ on-screen text (LLM vision is weak on small/cluttered numerals). OCR pre-extracts text so the agent gets both the image AND a transcript.
PaddleOCR (production-grade, CPU+GPU, multilingual, well-maintained). Optional via pyproject extras: pip install tdpilot-dpsk4[ocr]. Subprocess sidecar pattern so the 400MB model doesn't bloat the MCP server process.
ls src/td_mcp/vision/ # __init__.py, monitor.py, streamer.py exist (Phase B)
grep EXPECTED_MIN_TOOL_COUNT src/td_mcp/release_gates.py # should be 106 (after v2.5.1)src/td_mcp/vision/ocr.py— subprocess manager: spawn, JSON-lines protocol over stdin/stdout, lazy-init, 5-minute idle kill, restart-on-crashsrc/td_mcp/vision/ocr_worker.py— standalone worker script:paddleocr.PaddleOCR(use_angle_cls=True, lang='en'), accept image paths on stdin, emit JSON results on stdouttests/test_v25_ocr.py— fixture PNG with known text, mock subprocess for unit tests, optional@pytest.mark.skipif(not paddleocr_installed)integration testtests/fixtures/ocr_sample.png— known-text PNG (e.g., "Error: COMP missing parent") for golden-test
src/td_mcp/vision/streamer.py(ormonitor.py) — call OCR after capture; mergeocr_textinto vision payload; gracefully degrade when extras not installedtd_component/tdpilot_api_runtime.py— Phase B vision payload now includesocr_textfield; LLM gets both{type: "image"}and{type: "text", text: "Visible text (OCR):\n..."}pyproject.toml— add[project.optional-dependencies]section:[project.optional-dependencies] ocr = ["paddleocr>=2.7", "paddlepaddle>=2.6"]
README.md— document OCR extras + tradeoff (size, latency)CHANGELOG.md— v2.5.2 entry
TD capture (Phase B) → MCP server vision pipeline →
1. Save PNG to /tmp/tdpilot_screen_<hash>.png
2. Subprocess (if [ocr] installed): python ocr_worker.py < path → JSON
3. Merge ocr_text + bounding boxes into vision payload
4. Send to LLM with both image + text blocks
- Spawn on first OCR call (warmup ~5s; surface as
{"type": "status", "status": "ocr_warming"}to chat UI) - Keep alive after warmup
- Kill after 5min idle
- Restart-on-crash with exponential backoff (1s, 2s, 4s; give up after 3 attempts, log + continue without OCR for the turn)
→ stdin: {"image_path": "/tmp/tdpilot_screen_abc.png"}
← stdout: {"text": "Error: COMP missing parent\n/project1/foo", "boxes": [...], "confidence": [0.98, 0.95]}
No new MCP tool — OCR runs INSIDE the vision pipeline transparently. Optionally expose td_ocr_image(path) if explicit invocation is useful (defer decision; ship without first).
- Subprocess spawn lifecycle (mock subprocess; 3 tests)
- JSON-lines protocol roundtrip (mock subprocess; 2 tests)
- Crash-and-restart with backoff (mock subprocess; 2 tests)
- Vision-payload merge format (no subprocess; 2 tests)
- End-to-end with real paddleocr on
tests/fixtures/ocr_sample.png(@pytest.mark.skipif; 1 test)
pip install -e .[ocr] # extras install succeeds
uv run pytest tests/test_v25_ocr.py -v # all pass (subprocess tests + skip integration if extras absent)
uv run pytest tests/ --ignore=tests/agent_evals -x -q # no regressions; ~2023 pass
# Manual: run TD, send screenshot through Phase B path, verify ocr_text in chat-pipe log- Risk: PaddleOCR install fails on Windows/Apple Silicon. Mitigation: extras-only install; clear error message if install fails; agent works fine without OCR.
- Risk: First-run model download (~400MB) blocks first OCR call. Mitigation: lazy + status event so user sees "downloading OCR model…".
- Risk: OCR latency adds 200-500ms to every Phase B capture. Mitigation: make Phase-B-OCR opt-in via
OcrmodeCOMP param (off/auto). Defaultautowhen extras installed,offotherwise.
After this PR merges, mark v2.5.2-ocr as completed. Next phase: v2.5.3-tool-approval.
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.3-tool-approval
Tox rebuild: API .tox only (gate lives in chat-pipe runtime)
v2.4 added the User-Intent Gate (B-008 Bug 8 fix) at system-prompt level. That's first-line defense. Tool Approval adds a runtime gate: even with valid auth + intent, destructive tools require explicit click-through. Layered defense. Closes the residual concern from project_tdpilot_api_authmode_open_default.md memory about drive-by-RCE risk in Authmode=open.
grep "class TdpilotApiExt" td_component/tdpilot_api_extension.py # extension class exists
grep -c "Authmode" td_component/build_tdpilot_api_tox.py # Authmode param wired (≥1)tests/test_v25_tool_approval.py— ~15 tests across modes × gated tools × approve/deny/timeout
td_component/tdpilot_api_runtime.py—_check_approval(tool_name, args)called before dispatch; gated-tool list constanttd_component/tdpilot_api_web_callbacks.py— new POST/approveendpointtd_component/tdpilot_api_chat.html— approval banner UI with approve/deny + 30s countdown timertd_component/build_tdpilot_api_tox.py— registerApprovalmodeMenu COMP param:off/destructive_only/all. Defaultdestructive_only.CHANGELOG.md— v2.5.3 entry
APPROVAL_REQUIRED = frozenset({
"td_exec_python", # arbitrary code
"td_delete_node", # destructive
"td_restore_snapshot", # destructive
"td_disconnect", # network surgery
"td_rename_node", # only when target path is OUTSIDE the agent's own COMP
"snapshot_restore_scoped", # v2.3.0 addition; destructive
"td_set_content", # writes to DAT bodies; can be destructive
})Server → Client: {
"type": "approval_request",
"id": "<uuid>",
"tool": "td_delete_node",
"args": {"path": "/project1/foo"},
"timeout_ms": 30000
}
Client → Server (via POST /approve):
{
"id": "<uuid>",
"decision": "approve" // or "deny"
}
Inject tool_result: "User did not approve within 30s — tool denied." so the agent sees the denial as a normal tool error and can adapt (apologize, switch strategy, or ask the user explicitly).
- Layer 1: User-Intent Gate (Bug 8 fix, system-prompt level) — blocks destructive tools when user message doesn't authorize.
- Layer 2: Tool Approval (this phase, runtime level) — even if Layer 1 lets through, asks click-through.
- Layer 3: Auth (Authmode token/open) — gates entire
/sendendpoint. - Layer 4: Origin allowlist — rejects cross-origin browser CSRF.
All four layers compose. Each is opt-out individually if user needs unattended/headless operation.
- 1 per gated tool ×
Approvalmode=off(passes through unchanged) — 7 tests - 1 per mode (
off,destructive_only,all) ×td_exec_python× approve/deny/timeout — 9 tests, but overlap with above → net 8 new - 1 composition test: User-Intent-Gate-blocked tool also Tool-Approval-blocked (defense in depth) → 1 test
- 1 chat-UI render test (mocked WS message) → 1 test
uv run pytest tests/test_v25_tool_approval.py -v
uv run pytest tests/ --ignore=tests/agent_evals -x -q
# Manual: rebuild API tox, drag .tox into TD, set Approvalmode=destructive_only,
# send "delete node /project1/foo", verify banner appears- Risk: Breaks unattended / CI / headless workflows. Mitigation:
Approvalmode=offescape hatch; documented prominently in README. - Risk: Banner UX gets in the way during live performance. Mitigation: 30s timeout auto-denies (safe default); user can flip to
offper performance. - Risk: Race between approval response and turn timeout. Mitigation: turn budget (Phase C.9 thinking-budget) extends while awaiting approval.
After this PR merges, mark v2.5.3-tool-approval as completed. Next phases (4–7) are quick polish — can dispatch in parallel.
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.4-auth-fallback
Tox rebuild: None
The dpsk4 fork already cites ~/.tdpilot-dpsk4/.tdpilot-dpsk4.env in AGENTS.md naming pins, but the MCP-server auth code may still rely on env vars only (verify). Closes the cold-start auth-401 scenario from feedback_td_mcp_auth.md memory.
grep -rE "TD_MCP_SHARED_SECRET" src/td_mcp/auth_bootstrap.py # confirm current source
test -f ~/.tdpilot-dpsk4/.tdpilot-dpsk4.env # may or may not exist on dev machinesrc/td_mcp/auth_bootstrap.py— read fallback file whenTD_MCP_SHARED_SECRETenv var unset; one-shot migration on first launch (if env IS set, copy to file so subsequent restarts work)README.md+docs/GETTING_STARTED.md— document the fallback pathtests/test_v25_auth_fallback.py(new) — 5 tests
TD_MCP_SHARED_SECRETenv var (if set)~/.tdpilot-dpsk4/.tdpilot-dpsk4.envfile (single-lineTD_MCP_SHARED_SECRET=<value>)- Legacy
~/.tdpilot-api/api_key(back-compat) - None → MCP server starts in "no-secret" mode (open; print warning)
On startup, if env IS set and file is missing → write env value to file (0600 perms, atomic via os.rename from tmp). One-shot side effect. Log: "[auth_bootstrap] migrated TD_MCP_SHARED_SECRET env → ~/.tdpilot-dpsk4/.tdpilot-dpsk4.env".
- env-present, file-absent → use env
- env-absent, file-present → use file
- both present → env wins
- both absent, legacy present → use legacy + log deprecation
- file corrupt (not key=value) → ignore, log warning
uv run pytest tests/test_v25_auth_fallback.py -v
test -f ~/.tdpilot-dpsk4/.tdpilot-dpsk4.env && cat ~/.tdpilot-dpsk4/.tdpilot-dpsk4.env | grep -q TD_MCP_SHARED_SECRET
# Manual: unset env, restart MCP server, verify it still authenticatesAfter merge, mark completed. Independent of other phases.
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.5-td-release-card
Tox rebuild: None
TD 2025.32820 (May 2026) added Trace/Triangulate POP, DMX POP pipeline, Layer Mix TOP, RTX Video TOP, ST2110 I/O, color overhaul. Content already lives in project_td_2025_32820_features.md memory. Materialize as a queryable knowledge card.
ls src/td_mcp/knowledge/ # confirm knowledge corpus dir
grep -rl "td_2025" src/td_mcp/knowledge/ 2>/dev/null # may or may not have one alreadysrc/td_mcp/knowledge/td_releases/td_2025_32820.md— full release notes- Header: build number, date, OS support, breaking changes
- Sections: POPs additions (Trace, Triangulate), DMX pipeline, TOPs (Layer Mix, RTX Video), I/O (ST2110), color management changes
- Compatibility table
src/td_mcp/registry/knowledge_corpus_tools.py(or equivalent — check actual filename) — verify the new markdown file is picked up bytd_search_official_docs+td_get_release_delta
- Add to existing knowledge corpus tests: assert the new card is indexed and
td_get_release_delta("2025.32820")returns content
uv run python -c "from td_mcp.knowledge import load_corpus; print('td_2025_32820' in load_corpus())"
uv run pytest tests/test_knowledge_corpus.py -v1-hour task. Mark completed immediately after.
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.6-npm-stdio
Tox rebuild: None
When MCP server's Python logging goes to stdout, it mixes with JSON-RPC traffic and breaks Claude Desktop / Claude Code MCP framing. dreamrec/TDPilot v1.6.12 fixed this upstream. We forked before that fix → likely broken under Claude Desktop. Verify by reading our current npm/bin.js.
cat npm/bin.js | head -40 # inspect current spawn config
grep -E "stdio|stderr" npm/bin.jsnpm/bin.js— explicit stdio mode + stderr passthrough:const proc = spawn(pythonBin, args, { stdio: ['inherit', 'inherit', 'pipe'] // stderr piped }); proc.stderr.on('data', d => process.stderr.write(d)); proc.on('exit', code => process.exit(code));
tests/test_npm_wrapper.js(new, if doesn't exist) — smoke test asserting stdout contains only{-prefixed JSON lines and stderr contains the log marker
# Cold test in Claude Desktop / Claude Code MCP config
# Or: npx tdpilot-dpsk4 < /dev/null 2>/tmp/err > /tmp/out
# grep -c "^{" /tmp/out # stdout: only JSON
# grep -q "td_mcp" /tmp/err # stderr: has logsIndependent. Mark completed after.
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.7-check-updates
Tox rebuild: MCP only (new tool registered)
Read-only update awareness. Surfaces BOTH server-version drift AND .tox source-hash freshness so the agent can advise users on what to do next. Full auto-apply (td_self_update) defers to v2.7 paired with Tox Updater (see v2.7_IMPLEMENTATION_PLAN.md).
src/td_mcp/registry/lifecycle_tools.py— registertd_check_for_updatessrc/td_mcp/lifecycle/__init__.pysrc/td_mcp/lifecycle/update_check.py— GitHub Releases API client +.tox-source-hash.jsoncomparatortests/test_v25_check_updates.py— 8 tests (mock GitHub API)
@mcp.tool()
async def td_check_for_updates() -> dict:
"""Check GitHub Releases for newer tdpilot-dpsk4 versions.
Returns server-version comparison AND .tox source-hash freshness."""
return {
"server": {
"current": "2.5.0",
"latest": "2.5.1",
"has_update": True,
"url": "https://github.com/dreamrec/TDPilot_deepseekv4/releases/tag/v2.5.1"
},
"tox": {
"tdpilot-dpsk4.tox": {
"hash_matches": True,
"rebuild_needed": False
},
"tdpilot_API.tox": {
"hash_matches": False,
"rebuild_needed": True,
"reason": "source files modified since last build"
}
},
"advice": "Server has an update. Run `npx tdpilot-dpsk4@latest`. Also rebuild tdpilot_API.tox in TouchDesigner."
}GET https://api.github.com/repos/dreamrec/TDPilot_deepseekv4/releases/latest- Cache result for 1 hour (avoid hammering API)
- Graceful failure: return
{"server": {"check_failed": True, "reason": "..."}}instead of raising
- Mock GitHub API, version comparison correct (3 tests for newer/same/older)
.tox-source-hash.jsondrift detection (2 tests)- Cache: second call within 1h hits cache (1 test)
- Graceful failure on 5xx / network error (1 test)
- Tool registered & discoverable (1 test)
uv run pytest tests/test_v25_check_updates.py -v
grep "EXPECTED_MIN_TOOL_COUNT: int = 110" src/td_mcp/release_gates.py
# Manual: invoke td_check_for_updates from chat-pipe, verify advice string is actionableMark completed. Full update-apply path lives in v2.7.
Status: SHIPPED (v2.5.0, 2026-05-19)
Branch suggestion: claude/v2.5.8-log-receiver
Tox rebuild: API only
Drop first if v2.5 schedule slips.
The plan: ship a Log Receiver operator. Tail MCP-server stderr (and chat-pipe internal logs) into a TD Table DAT for in-app debugging. Multiplies the value of activity_log + journal_hints.
td_component/tdpilot_api_log_tail.py— log buffer + Table-DAT renderertests/test_v25_log_receiver.py— 10 tests
td_component/tdpilot_api_chat.html— add "Logs" tab (lazy-loaded)td_component/build_tdpilot_api_tox.py::_API_TOX_SOURCE_FILES— addtdpilot_api_log_tail.py
If chat HTML restructure feels heavy, ship without UI — table DAT alone is debuggable from Textport.
Mark completed or deferred_to_v2.6.
pyproject.toml # version = "2.5.0"
src/td_mcp/__init__.py # __version__ = "2.5.0"
.claude-plugin/plugin.json # version
.claude-plugin/marketplace.json # plugins[0].version (drives Update button)
npm/package.json # version
mcp/manifest.json # version
td_component/mcp_webserver_callbacks.py # API_VERSION → forces tox rebuild
Plus EXPECTED_MIN_TOOL_COUNT: int = 110 in release_gates.py (assuming all 5 new tools land; if log_receiver slips, → 109).
README.md, npm/README.md, plugin_README.md, docs/API_REFERENCE.md, docs/USER_GUIDE.md, docs/GETTING_STARTED.md, skills/tdpilot-dpsk4-core/SKILL.md, skills/tdpilot-dpsk4-production/SKILL.md (if exists), CLAUDE.md (user's global instructions — note: NOT in repo, mention in CHANGELOG instead), CHANGELOG.md top entry, .claude-plugin/marketplace.json description field, npm/package.json description, GitHub repo description (via gh repo edit dreamrec/TDPilot_deepseekv4 --description "...").
Both .tox files need rebuild. Canonical Textport recipe in feedback_td_tox_rebuild_recipe.md memory. Auto-mirror (v2.2.1+) syncs to main repo.
uv run pytest tests/ --ignore=tests/agent_evals -x -q
uv run --extra dev ruff format --check src tests scripts td_component
uv run --extra dev ruff check src tests scripts td_component
uv run python scripts/check_versions.py
uv run python scripts/check_tox_freshness.py
uv run python scripts/check_tox_api_freshness.pyuv run python scripts/build_plugin_zip.pygit tag v2.5.0 -m "TDPilot DPSK4 v2.5.0 — Agent self-awareness + safety + distribution polish"
git push origin v2.5.0
gh release create v2.5.0 \
--title "v2.5.0 — Agent self-awareness + safety + distribution polish" \
--notes-from-tag \
td_component/tdpilot-dpsk4.tox \
td_component/tdpilot_API.tox \
tdpilot-dpsk4.plugin.zip \
tdpilot-dpsk4.mcpbTrusted Publisher OIDC handles this automatically on tag push via .github/workflows/release-assets.yml. Do NOT add NPM_TOKEN — per feedback_npm_trusted_publisher_oidc.md memory.
After tag, edit description to mention v2.5 highlights. This is what users see on the plugin panel.
| Risk | Phase | Probability | Impact | Mitigation |
|---|---|---|---|---|
OCR [ocr] extras fail on Windows / Apple Silicon |
2.5.2 | Med | Med | Optional install, clear error, agent works without OCR |
| Tool approval breaks unattended CI/headless | 2.5.3 | Med | High | Approvalmode=off escape hatch + README documentation |
| Activity log ring grows memory unbounded | 2.5.1 | Low | Low | deque(maxlen=200) + slots=True |
| Journal hints redundant with B-007 / cycle-detect | 2.5.1 | Low | Low | Tests pin distinct trigger thresholds (count=2 vs 3 vs 4) |
| Auth fallback collides with legacy storage | 2.5.4 | Low | Med | Precedence rules tested explicitly |
td_check_for_updates hammers GitHub API |
2.5.7 | Med | Low | 1h cache; graceful 5xx fallback |
| Tool count drift fails CI | All | Med | Low | check_versions.py runs pre-push; bump EXPECTED_MIN_TOOL_COUNT per phase |
If you're picking up v2.5 work in a fresh session:
- Read this file fully (you're doing it now).
- Check the phase-overview table at §1 — find the first row whose
Statusisnot_startedorin_progress. - Follow that phase's section (§2–§9) to the letter:
- Pre-flight checks → Files to create → Files to modify → Tests → Validation gates → Update status
- Before committing: run validation gates AT MINIMUM. Pre-push sweep ideally.
- PR title format:
feat(v2.5.N): <one-line description>(matches v2.4 convention). - After PR merges to
main: edit this file's §1 overview table to setStatus: completed. Push the doc update.
Run §10 release engineering. After gh release create v2.5.0 succeeds, mark this entire plan archived and create v2.5.1_IMPLEMENTATION_PLAN.md (patch release) if any follow-up fixes are needed, OR proceed to v2.6_IMPLEMENTATION_PLAN.md.
Mark the phase Status: blocked and write a one-paragraph note under the phase explaining what blocks. Move to the next independent phase (e.g., if v2.5.2 OCR is blocked on PaddleOCR install woes, jump to v2.5.4 auth fallback).
End of v2.5 plan. Next: v2.6_IMPLEMENTATION_PLAN.md (retrieval + knowledge).