744aabee96
* fix(mcp): keep spawner attribution on a spawned session's first turn A session started through spawn_session_kandev never learned who spawned it, so it had no way to report back. The MCP handler did prepend a <kandev-system> attribution block, but the first-turn canonicalizer (sysprompt.canonicalizeKandevContext) drops every system block it cannot attribute to server state — and the spawn block was not on the trusted list, so it was deleted before the agent ever saw it. Spawns are always a first turn, so this happened every time. Generate the block at the launch site instead, from server-resolved identity, and whitelist that exact content for the injector — the same pattern entity references already use: - config/prompts/spawned-session.md holds the attribution template. - sysprompt.SpawnedSessionContext builds it; sysprompt.StripTags (lifted out of the handlers' stripSystemTag) keeps embedded IDs from closing the block early. - LaunchSessionRequest.SpawnOrigin carries the spawner identity and is kept off the wire (json:"-") so a WS client cannot forge a trusted system block. - startTask prepends the block and passes the identical content as trusted content to both the task and Office injectors. Its trailing env/route parameters move into a startTaskOptions struct rather than growing the positional list again. - The MCP handler now only fills SpawnOrigin (including the spawner's session name) and passes the prompt through untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(mcp): derive spawn attribution from the verified spawner session Addresses both PR review findings. CodeRabbit: spawnOrigin copied sender_task_id / sender_session_id straight out of the request, so an unknown or cross-task sender_session_id became trusted launch attribution — the spawned agent would be told to report to a session that never asked for it. Resolve the spawner session once, up front, require it to belong to the claimed sender task, and derive the origin (and the inherited agent profile) from that row. An unverifiable claim now yields no attribution instead of a forged one. This also drops a duplicate session lookup. Codex: passthrough profiles skip the Kandev MCP wrap, so the new attribution never reached a spawned passthrough session even though it gets MCP configured and can reply. Give that path plain-text attribution (no <kandev-system> markup, which would show up raw in the TTY the user is watching). The wrap branch moves into applyLaunchPromptContext, which keeps startTask under the nesting limit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Kandev Agent <agent@kandev.dev> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>