[Bug] Control tokens leaked to user output in agentic task notifications
Bug Description
claude code seemed to leak internal control tokens like <task-notification> raw into user-visible space: Monitor(Waiting for Plan agent seam-verification results)
Monitor started · task b8u09ryal · timeout 600s
Thought for 10s
The Plan agent is still reading the codebase — I'll finalize and present the plan as soon as it reports back.
system[SYSTEM NOTIFICATION - NOT USER INPUT]
This is an automated background-task event, NOT a message from the user.
Do NOT interpret this as user acknowledgement, confirmation, or response to any pending question.
<task-notification>
<task-id>aeddb425e7a993fff</task-id>
<tool-use-id>toolu_01Y3thpuc9tNyKkbLLSGXhbP</tool-use-id>
<output-file>/private/tmp/claude-501/-Users-benmathes-coding-felicis-exoskeleton-exo1/8a2c0439-0ebf-464a-a744-7d62ae7ef802/tasks/aeddb425e7a993fff.output</output-file>
<status>completed</status>
<summary>Agent "Draft implementation plan + verify seams" finished</summary>
<note>A task-notification fires each time this agent stops with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note>
<result>Plan complete. The full implementation plan is above. Key summary:
Implementation Plan Summary
Feature: Weekly OSS Traction Sourcing email digest — headless two-phase skill run (web-isolated Phase 1, MCP-only Phase 2), rendered to branded HTML email + WeasyPrint PDF attachment, sent to EmailConfig subscribers via cron.
Verified seams (all file:line references confirmed by reading):
- run_anthropic_project() (anthropic_project_runner.py:257) — needs 3 new optional kwargs: allowed_tools, create_session, store_prompt_full. Subprocess stdin JSON gets allowed_tools key; _sdk_subprocess.py:236 reads it with fallback to current default. partner_email must resolve to an allowlisted Person (email_handler pattern) — use settings.DIGEST_RUNNER_EMAIL (ben@felicis.com) for the cron identity.
- Idempotency (send_slack_digest.py:107-133) — SystemEvent.objects.filter(event_type="oss_sourcing_digest_sent", created_at__gte=window_start).exists() guard; --force bypasses; record after successful send with payload (week key, recipients, tool_calls, duration).
- Email attachments — EmailAttachment NamedTuple (filename, content bytes, mimetype) added to backends/base.py Protocol; gmail.py:~また150 and ses.py MIME assembly switch from MIMEMultipart("alternative") to outer mixed wrapping the alternative part + MIMEApplication parts; memory.py records attachments for test assertions. send_email() api.py:39 gains attachments: Sequence[EmailAttachment] | None = None.
- Skill prompt from DB — MarkdownContext.objects.get(entity_type="skill", feature="oss_traction_sourcing") via existing get_skill_prompt() helper in core/skills/loader.py:44. Flag: seed frontmatter name: oss-traction-sourcing-test — seeding uses filename stem (oss_traction_sourcing) as feature key (seed_contexts.py:88 confirmed), frontmatter name is claude.ai-facing only. No blocker, but rename the "-test" suffix in the same PR.
- Namespace floor — namespaces.yaml defines: mcp_market, mcp_pipeline, mcp_portfolio, mcp_finance, mcp_lp, mcp_canonical. Portfolio-universe ("IN" bucket) check reads mcp_portfolio.portfolio_companies (verified in semantic layer YAML) — mcp_finance NOT needed. Floor = {mcp_canonical, mcp_market, mcp_pipeline, mcp_portfolio}.
- WeasyPrint — add weasyprint>=62 to pyproject [project.dependencies]; apt packages libpango-1.0-0 libpangoft2-1.0-0 libgdk-pixbuf-2.0-0 added to bin/setup-self-server:31 apt block; macOS dev needs brew install pango documented in README + checked in bin/setup-self-dev. Font note: Helvetica falls back to Liberation Sans on Linux — visually acceptable, add fonts-liberation to apt list.
- Cron — exact line format verified against crontab.production:61-66 pattern (cron-wrap + logs). New lines for 0 14 1 both files + deployment.md table row + DST comment.
- Tests to mirror: test_send_slack_digest.py (command-level, mocks service), test_email_backends.py (memory backend assertions), new test_oss_sourcing_digest.py integration test with unittest.mock.patch("core.services.oss_sourcing_digest.run_anthropic_project") two-call side_effect.
Risks flagged: (a) Phase 1 web run can exceed max_turns on tracker disagreement — set per-phase max_turns overrid
Environment Info
- Platform: darwin
- Terminal: Apple_Terminal
- Version: 2.1.193
- Feedback ID: c8b87286-e893-4b8a-97e1-1fc9f72440a5
Errors
[]
<img width="1492" height="1174" alt="Image" src="https://github.com/user-attachments/assets/006aa96e-bcdb-407d-880d-a0e21f5a7c34" />