Nous Research has shipped a change to Hermes Agent. Its delegate tool can now run subagents asynchronously. Per the announcement, delegated work no longer blocks the parent chat.
Hermes Agent is an open-source personal agent from Nous Research. A parent agent can spawn child agents, called subagents, to fan out work. Until now, that delegation made you wait.
The update was announced on X by Nous Research and co-founder Teknium. Existing users enable it by running hermes update.
Hermes Agent now supports asyncronous subagents!
The existing delegate tool, which your agent uses to spawn subagents to fan out and do work, no longer blocks your chat!
To access now, `hermes update`, and enjoy! pic.twitter.com/6hN94wpRLW
— Teknium 🪽 (@Teknium) June 15, 2026
What are Subagents
The delegation tool is delegate_task. It spawns a subagent, which is an isolated child agent. Each child gets its own conversation, terminal session, and toolset.
Only the final summary returns to the parent. The parent’s context never sees the child’s intermediate tool calls or reasoning. That keeps the parent’s context window small.
Isolation is strict. Subagents start with a completely fresh conversation. They have no knowledge of the parent’s history. The parent must pass everything through the goal and context fields.
Subagents inherit the parent’s API key, provider configuration, and credential pool. That credential pool enables key rotation on rate limits. You can route subagents to a cheaper model through config.yaml.
What Was Blocking, and What Changed
In source, delegate_task is synchronous. The parent blocks inside the tool call until every child completes. Your chat stays frozen during that wait.
That design prevented several workflows. You could not start a long agent and keep working. You could not check in on a run or steer it mid-flight.
Nous built the non-blocking path in the open. Issue #5586 adds an async_delegation toolset. It spawns a background agent and returns a task_id immediately. The announcement confirms async subagents are now available.
The async tools cover the full lifecycle:
- delegate_task_async — spawn a background agent, return a task_id
- check_task — non-blocking status plus recent output
- steer_task — inject a message into a running task
- collect_task — block until done, then return the full result
- cancel_task — stop a running task
- list_tasks — all async tasks in the session
Background agents run as in-process threads. They reuse the same AIAgent machinery, credentials, and toolsets as delegate_task.
Synchronous vs Asynchronous Delegation
DimensionSynchronous delegate_taskAsynchronous delegation (async_delegation, #5586)Parent chatBlocks until all children finishReturns a task_id immediately; chat stays freeControl while runningNone — you waitCheck status, steer, collect, or cancel per taskExecutionParent waits inside the tool callBackground in-process threadsContext costOnly the final summary returnsOnly the final summary returnsIsolationFresh conversation per childFresh conversation per childBest forQuick fan-out you wait onLong tasks you run alongside the chatDurabilityNot durable across turnsSingle-session; ACP (#4949) targets cross-turn
‘+txt;
chatlog.appendChild(d); chatlog.scrollTop=chatlog.scrollHeight; resize();
}
function setBanner(){
if(busy() && mode===’sync’){
banner.className=”banner blk”;
banner.textContent=”Chat blocked — parent is waiting for subagents to finish.”;
chatin.disabled=true; sendbtn.disabled=true; chatin.placeholder=”Blocked while subagents run…”;
} else if(busy() && mode===’async’){
banner.className=”banner ok”;
banner.textContent=”Non-blocking — keep chatting while subagents run in the background.”;
chatin.disabled=false; sendbtn.disabled=false; chatin.placeholder=”Type a message to the parent agent…”;
} else {
banner.className=”banner ok”;
banner.textContent=”Idle — delegate subagents to see the difference.”;
chatin.disabled=false; sendbtn.disabled=false; chatin.placeholder=”Type a message to the parent agent…”;
}
}
function renderStats(){
root.querySelector(‘#s-run’).textContent = tasks.filter(function(t){return !t.done;}).length;
root.querySelector(‘#s-done’).textContent = doneCount;
root.querySelector(‘#s-msg’).textContent = msgWhileBusy;
}
function delegate(){
if(tasks.length){ return; }
tasksEl.innerHTML=”;
addMsg(‘you’,’delegate_task(tasks=[ 3 subagents ])’,’you’);
TASKS.forEach(function(spec,i){
var id=’t’+(seq++);
var card=document.createElement(‘div’); card.className=”task”; card.id=id;
card.innerHTML=’
‘+spec.goal+’‘+spec.tool+’
‘+
‘
queued…
‘;
tasksEl.appendChild(card);
var t={ id:id, spec:spec, step:0, prog:0, done:false, el:card };
tasks.push(t);
runStep(t, i*250);
});
setBanner(); renderStats(); resize();
}
function runStep(t, delay){
setTimeout(function(){
if(t.done) return;
var stateEl=t.el.querySelector(‘.state’);
var barEl=t.el.querySelector(‘.bar > i’);
stateEl.textContent=”▸ “+t.spec.steps[t.step];
t.prog=Math.round(((t.step+1)/t.spec.steps.length)*100);
barEl.style.width=t.prog+’%’;
t.step++;
if(t.step < t.spec.steps.length){
runStep(t, 700+Math.random()*500);
} else {
t.done=true; t.el.classList.add(‘done’);
stateEl.textContent=”✓ summary returned to parent”;
doneCount++;
addMsg(‘parent’,’Subagent summary [‘+t.spec.goal+’]: completed, result merged into context.’,’par’);
setBanner(); renderStats();
}
}, delay||0);
}
function send(){
var v=chatin.value.trim(); if(!v) return;
if(busy() && mode===’sync’) return;
addMsg(‘you’, v, ‘you’);
if(busy()){ msgWhileBusy++; }
chatin.value=””; renderStats();
setTimeout(function(){ addMsg(‘parent’,’Acknowledged. I will fold that into the run.’,’par’); }, 400);
}
function reset(){
tasks=[]; doneCount=0; msgWhileBusy=0;
chatlog.innerHTML=”; chatin.value=””;
tasksEl.innerHTML=’
No active subagents. Each runs in an isolated context and returns only a summary.
‘;
setBanner(); renderStats(); resize();
}
root.querySelectorAll(‘.mode’).forEach(function(b){
b.addEventListener(‘click’, function(){
root.querySelectorAll(‘.mode’).forEach(function(x){x.classList.remove(‘active’);});
b.classList.add(‘active’); mode=b.getAttribute(‘data-mode’); setBanner();
});
});
delbtn.addEventListener(‘click’, delegate);
resetbtn.addEventListener(‘click’, reset);
sendbtn.addEventListener(‘click’, send);
chatin.addEventListener(‘keydown’, function(e){ if(e.key===’Enter’) send(); });
// Auto-resize: measure the component’s own offsetHeight and notify the parent.
function resize(){
var h = root.offsetHeight + 40;
if(window.parent && window.parent !== window){
window.parent.postMessage({ type:’mtp-hermes-resize’, height:h }, ‘*’);
}
}
window.addEventListener(‘load’, function(){ setBanner(); renderStats(); resize(); setTimeout(resize,300); });
})();
