Repository navigation
Conversation
Additive v1 schema changes for background subagents:
- task_started / task_finished log entries (status, summary, error, usage,
duration, last tool, run count)
- optional user-message origin { _tag: 'task-notification', taskIds } so
runtime-written turns are distinguishable; old logs decode unchanged
- task-progress ephemeral delta part
SessionControls queues now carry an origin, adjacent queued task
notifications drain as one message, and runningAgentIds exposes the
running registry. AgentRuntime and Session.send pass origins through.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
- subagent tool: run_in_background for dispatch, fork, and resume; the call returns a receipt once the agent has started - BackgroundTasks service: per-run task scopes forked from the session scope, durable task rows, live progress, and notification delivery (follow-up to a running launcher, otherwise the root: follow-up when busy, a synthetic task-notification wake when idle; coalesced) - session API: backgroundTasks, backgroundTaskChanges, stopTask, awaitBackgroundIdle; interrupt() leaves background tasks running; stop() stops them with deferred notices; close records them stopped; reopening rebuilds the registry and closes orphaned runs - list_agents, stop_agent, send_message model tools (agentControlTools) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
Install list_agents, stop_agent, and send_message next to the subagent tool, and tell the coding agent when to launch subagents in the background. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
runPrompt now waits after the prompt's own turn until background agents and their task-notification turns are done, and reports the root's latest outcome. Agents still running after --background-timeout seconds (default 600) are stopped; a signal while waiting stops them too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
- SUBAGENTS rail: BG badge, status from the task rows, X STOP hint; the rail header and activity label count running background agents - x on a selected running background agent stops it (session.stopTask) - a task-notification wake renders as an AGENTS notification row with the per-agent summaries instead of a USER row - line renderer prints [background] start/finish lines and a [notification] line for wakes; JSON verbose mode encodes task-progress Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
Fixture with a running and a finished background agent plus a task-notification wake; checks the rail badge and counts, the AGENTS notification row, and stopping the selected agent with x. Runs with FOLD_TUI_TERMINAL_TEST=1 like the other terminal-control tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
…eporting idle
- list_agents used Schema.Struct({}), whose JSON Schema root is an anyOf
(an empty struct also accepts arrays). OpenAI's strict tool schemas
reject that, so every Codex/OpenAI request failed in prepareTools. Use
Tool.EmptyParams like other parameterless tools.
- awaitBackgroundIdle could resolve between a run's task_finished row and
the queueing of its notification, so a headless run exited before the
last wake. Runs now count as unsettled until their notification is
queued, in the same state update.
- Regression tests: every tool the coding and RLM modes advertise (root,
subagent, and fork-agent tools, with and without RPI) converts through
the OpenAI provider's toCodecOpenAI to an object root without
anyOf/oneOf; awaitBackgroundIdle watched from before a run ends waits
for its notification turn.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a13295-e128-724d-bb90-666e8fbf2d01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
HumanLayer Task
Why the change
Subagents can now run in the background while the launching agent keeps working, and the launcher is notified when each one finishes, the same way Claude Code's background agents behave, so hosts like HumanLayer can show and control them through one surface.
Special things to note
task_started/task_finishedentries and an optionaloriginonuser-message. Both are additive, and v1 logs still decode (there are tests for this). Exhaustive matches in fold-cli were updated for the new tags.interrupt()with no target now stops only foreground work; background tasks keep running and still notify.stop()and closing the session stop them. A stop the model makes withstop_agentsends no notification, butstopTaskfrom the host does.codex/gpt-5.6-terra): two background agents, a wake per finish, then a clean exit; andlist_agents→stop_agent→list_agents. Those runs caught two bugs (alist_agentsschema OpenAI rejects, and an exit before the last notification) that are fixed here with regression tests.Change outline
One background run, from launch to notification:
New durable rows and the user-message origin:
Public surface:
subagent tool params { description?, prompt, agent?, agent_id?, fork?, skill?, + run_in_background? } +agentControlTools() → list_agents {}, stop_agent { agent_id }, send_message { agent_id, message } FoldSession + backgroundTasks: Effect<ReadonlyArray<BackgroundTask>> + backgroundTaskChanges: Stream<ReadonlyArray<BackgroundTask>> + stopTask(taskId): Effect<boolean, SubagentNotFoundError> + awaitBackgroundIdle: Effect<void> ~ interrupt(): foreground only; background tasks keep running foldcode + --background-timeout <seconds> # --prompt waits for background agents (default 600)BackgroundTaskfields (taskId, toolCallId, parentAgentId, agentType, description, prompt, status, isBackgrounded, startedAt/endedAt/notifiedAt, usage, lastToolName, progressSummary, summary, error, runCount) map 1:1 onto HumanLayer'ssession_background_taskstable.Where it lives:
Demo of the same feature in HumanLayer (Claude SDK side):
background-agents-demo.mp4