npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@argszero/cordis-plugin-team-delegation-guard

v0.1.0

Published

Withdraws the legacy delegation tools (subagent/subagent_fork) from every agent the Agent Teams runtime owns, so a Team session's delegation goes through the Team tools alone. On Web/Desktop the Agent Teams bundle's own `disabled` patches hit host-plane r

Readme

@argszero/cordis-plugin-team-delegation-guard

Withdraws the legacy delegation tools (subagent, subagent_fork) from every agent the Agent Teams runtime owns, so a Team session's delegation goes through the Team tools alone.

Source discussion: #7642 — Agent Teams bundle 在 Web/Desktop 未禁用 subagent.

npm install @argszero/cordis-plugin-team-delegation-guard
# profile / bundle layer; mount it anywhere
- insert:
    - id: team-delegation-guard
      name: '@argszero/cordis-plugin-team-delegation-guard'

Nothing else to configure. The plugin reads as inert in any composition that does not mount the Agent Teams runtime.


The problem it holds the composition to

Mount the Agent Teams bundle on Web/Desktop and one session offers two mutually incompatible delegation surfaces at once:

| surface | tools | |---|---| | Agent Teams | spawn_teammate, send_message, list_agents, interrupt_agent, wait_agent, team_task_* | | legacy direct delegation | subagent, subagent_fork |

The Team versions of send_message / list_agents / interrupt_agent are registered into each agent's own layer, so they shadow the preset's same-named continuable-child controls. subagent and subagent_fork have no Team twin, so they survive. A model that delegates through subagent — the path its own tool description teaches, and the one it takes when nobody mentions Teams — creates a child that is not a Team member:

subagent({...})                -> child runs and returns normally
list_agents()                  -> [{"target":"lead","role":"lead",...}]   // the lead alone
send_message({target:"<id>"})  -> Error: active teammate "190afdd6-…" not found

The error names no alternative, and the Team policy text never says that this session's send_message only accepts Team members. Every ordinary delegation on such a session is a dead end.

Why the bundle's own patch cannot fix it

experimental/agent-team-profile/cordis.patch.yml:4-14 disables the four legacy rows by id, and the bundle README states twice that ordinary subagent delegation is disabled (README.md:12, :49). On Web those ids belong to the host plane, and bundle/web-app/cordis.patch.yml:504-514 had already disabled all four — the profile's patch re-sets an already-false flag and is silently inert. No warning is produced, because the ids do match rows.

The rows the model actually sees are declared by the preset plane (bundle/web-app/presets/standard.patch.yml:80-118, and the ptc / cordis presets). A top-level patch cannot reach a preset row:

  • vendor/include/src/index.ts buildMap recurses only into same-level group rows, and an unmatched id is skipped;
  • scripts/verify-cordis-config.ts::validatePresetPlaneSeparation enforces that a row belongs to exactly one plane.

That is a deliberate two-plane architecture, and this plugin does not pretend otherwise — see What this is not.

What the plugin does

For every agent whose scope carries the Team tool set, it removes the legacy delegation names that agent can still see, using the seam the runtime already provides:

agent.ctx.tools.restrict({ deny: [...namesVisibleToThatAgent] })

The Team tool set is the signal. @deepseek-ai/dsh-experimental-tool-agent-team registers spawn_teammate into agent.ctx for every agent the Team runtime owns (tool-agent-team/src/index.ts:164-176), and nothing else in the tree ever registers that name. So:

  • Team absent → no marker ever appears → the guard does nothing. Whichever delegation tool the composition exposes is the composition's own choice.
  • Team present → agents it installs tools for lose the legacy names; agents it does not own (a plain subagent, another session) keep theirs.
  • Upstream adopts the core-side fix → subagent is no longer visible → the guard finds nothing to deny and goes inert again, with no configuration change and no version pin.

Three properties of the seam are what make this precise instead of approximate:

  1. restrict() filters the inherited surface only. core/tools/src/index.ts view() applies restrictions to the global layer and every non-own ancestor layer, then merges the scope's own registrations after the filter, outside it. Preset rows are an ancestor contribution, so they are maskable; the Team tools are an own-layer contribution, so they are not. That asymmetry is exactly what the fix needs.
  2. restrict() throws on a name it cannot resolve rather than ignoring it (core/tools/src/index.ts:1096-1122). So the deny list is built from the live view, never from a constant. A name that turns out to be own-layer is dropped and reported on its own instead of taking the whole batch down with it.
  3. The restriction is owned by agent.ctx. It lifts with the agent, and leaves no residue on the ancestor plane.

The three Team-shadowed controls are deliberately not denied

send_message, interrupt_agent and list_agents are in the four rows the bundle disables, but denying them here would be a no-op: Team registers all three in the agent's own layer, which restrict() exempts by construction. The default deny list therefore covers only the names the seam can actually reach. Listing them would look like coverage without being coverage, which is the failure mode this plugin exists to correct.

Configuration

| field | default | meaning | |---|---|---| | mode | enforce | enforce masks the names, warn reports them and changes nothing, off disables the guard | | markers | ['spawn_teammate'] | tool names that mark an agent as Team-owned; replaces the default | | deny | ['subagent', 'subagent_fork', 'subagent_codex', 'subagent_claude_code'] | legacy delegation names to withdraw; replaces the default |

- set:
    - id: team-delegation-guard
      config:
        mode: warn          # see what the composition leaks before enforcing
        deny: ['subagent']

subagent_codex and subagent_claude_code are the one-shot subagent providers, declared disabled: true by default in presets/standard.patch.yml. They are on the default list because a composition that deliberately enabled them under Team lands in the same trap, and because a name that is not registered costs nothing — the list is filtered against the live view before use.

Ordering

The guard and tool-agent-team are independent mounts that both work off agent/created, so either may run first. The guard leaves an agent undecided until its marker appears, and rechecks undecided agents on tools/change — an unfiltered registry notification emitted by every registration and every restriction. Each agent is decided once, so a later change cannot stack restrictions.

What this is not

  • Not the core-side fix. The recommended change is a per-row disabled: !!js "ctx.get('agentTeams') !== undefined" on the four legacy child-control rows in presets/standard|ptc|cordis.patch.yml — per row, not on the whole delegation group, which also carries workflow (headless Team snapshots retain it). When that lands, this plugin goes inert by itself.
  • Not a roster change. It cannot make a subagent child into a Team member. That is the roster, in @deepseek-ai/dsh-experimental-agent-team, where tryMembership returns undefined for a subagent-descriptor child (agent-team/src/roster.ts:92-122).
  • Not a policy document. It changes which tools exist, not what the model is told about them. If the composition wants delegation to remain possible alongside Team, it should say so in the Team tool descriptions.

Verification

npm test        # 18 behaviour arms + 6 packaging arms

The behaviour suite drives the real @deepseek-ai/cordis context, the real ToolRuntime, and the real scope chain linking a preset-plane ancestor scope to an agent scope; only the agent registry is stubbed. Enforcement arms are paired with control arms — an agent the Team runtime does not own must keep subagent, and an own-layer registration must survive the withdraw — because a guard that removes tools in every composition would be worse than one that removes none.

The packaging suite asks npm itself (npm pack --dry-run --json) what the tarball would contain, then requires the entry's relative import closure to be inside it. It has already caught one release defect in this package: a file declared in files that did not exist is omitted from the tarball with no warning at all.

Compatibility

Verified against dsh 0.1.7-rc.1 (source HEAD 46a7f68b09). The peer range spans the prerelease lines in which the restriction seam is unchanged: 0.1.5-rc.3 through 0.1.7-rc.1 — the view() / restrict() logic was compared across those releases and differs only in an internal accessor name. The plugin uses no private API: ctx.agents.list/get, ctx.tools.get, agent.ctx.tools.restrict, and agent/created / agent/disposed / tools/change.

License

MIT