AEV-2026-0051
Ateles dispatches an agent's tools from a harness allowlist maintained independently of its own canonical grant
GitHub issue 803 against markmhendrickson/ateles, opened 7 September 2026, reports zero of forty agents holding parity between their canonical agent_grant and the separately authored harness field their dispatcher actually reads. This entry independently cloned the repository's current default branch and confirmed the mechanism directly: no derivation connects the two representations, a claude dispatch unconditionally widens every restricted agent's own reach with a further tool entry no grant authorizes, and the dedicated enforcement proxy for grant tool capabilities carries no executable reference anywhere on the dispatch path this entry read.
Affected
- Organisation
- markmhendrickson
- Product
- Ateles (markmhendrickson/ateles)
- Component
- lib/daemon_runtime/agent_loader.py (AgentLoader, AgentDefinition.tools), lib/daemon_runtime/grant_checker.py (GrantChecker, AgentGrant._parse), execution/daemons/apis/skill_runner.py (_provider_command and the claude allowed_tools construction), and execution/mcp/mcp_tool_grant_proxy/proxy.py
- Versions
- The repository's current default branch as of 7 September 2026, commit 27101189c285c959c47dcb66c99669022dfe489a. Pull request 807's own branch, docs/register-decision-86-tool-grant-grammar at commit aea170e557fdc40117f563988ba0c1824a87f822, is design only and changes none of the affected source.
- Configurations
- Any agent_definition entity whose tool_allowlist is not the bare wildcard, dispatched through the claude provider.; Any agent_grant entity, of the thirty one the issue reports, that declares no tool colon prefixed capability, which the issue states is all of them.; Any dispatch routed through the codex or cursor provider, whose own command construction carries no tool scoped allowlist flag at all.
Execution authority facts
Fields the evidence does not establish are shown as unknown rather than guessed.
- Intended task
- Dispatch a role agent through a harness provider with the exact tool reach its own canonical grant authorizes, so that a governance write to the grant is the operative description of what the agent may call
- Agent
- Ateles's own daemon runtime dispatch path, specifically skill_runner.py's provider command construction
- Delegating actor
- The operator or migration that authored the agent's own agent_grant entity and, separately, its agent_definition.tool_allowlist field
- Action
- Built a claude provider command whose effective tool reach is read from agent_definition.tool_allowlist plus an unconditional appended Neotoma wildcard entry, confirmed directly by this entry's own reading of skill_runner.py, with no step deriving that reach from agent_grant or comparing the two
- Target resource
- The full Neotoma MCP tool surface, including delete_entity, merge_entities and register_schema, appended to every restricted claude dispatch regardless of what its own allowlist or grant names
- Environment
- Any Ateles daemon dispatch using the claude, codex or cursor provider
- Credentials used
- unknown
- Privileges available
- Whatever the appended Neotoma MCP server itself accepts from an authenticated bearer token the dispatch already carries, unconstrained further by any grant check on the path this entry read
- Authority presented
- agent_definition.tool_allowlist, in the harness's own grammar, confirmed directly by this entry to be read and parsed with no reference to agent_grant of any kind
- Authority required
- Whatever agent_grant.capabilities records for the agent, in a distinct grammar, tool colon server colon tool op strings, confirmed directly to be looked up through an entirely separate code path keyed by aauth_sub
- Applicable policy
- Decision 42, an architecture ruling this entry could not read directly but which issue 803 and pull request 807 both describe consistently as requiring the harness field to be derived from the grant at load or held equal to it by a parity test
- Approval mechanism
- none
- Required approver
- unknown
- Independent approval
- no
- Action binding
- None found. This entry confirmed directly that agent_definition.agent_grant, a field whose name suggests a link, is a two valued role string rather than a reference to any specific grant entity, and that no function in the repository reads both agent_grant and agent_definition.tool_allowlist for the same principal
- Sequence context
- The mismatch is structural and present at every dispatch through the affected path, not a one time event; this entry's own evidence is a direct reading of the code that would run on any qualifying dispatch, not a captured trace of one that did
Impact
- Consequence
- Every restricted agent dispatched through the claude provider receives full access to the Neotoma MCP server's own tool surface regardless of its own declared allowlist or any grant, confirmed directly by this entry's own reading of the unconditional append in skill_runner.py
- Reach
- systemic
- Reversibility
- unknown
- Detectability
- No error, warning or test failure is produced by the current default branch's own lint or test suite for this gap. The harness field's own linter validates only its own grammar and carries no reference to agent_grant at all, confirmed directly by this entry's own reading of scripts/linters/validate_tool_allowlist.py
- Propagation
- potential
- Recovery
- Not shipped. Pull request 807 registers a design only proposal for the grammar a future parity test and migration would require, targets another unmerged branch, and changes no grant, allowlist or dispatch code as of this entry
Evidence
Primary sources
- Harness allowlist is a second home, not a grant derivation: decision 42's parity test does not exist and 0 of 40 agents hold parity (markmhendrickson/ateles (GitHub Issues))
Supporting sources
- docs(foundation): register decision 86, the grammar by which a grant names a tool (markmhendrickson/ateles (GitHub Pull Requests))
- markmhendrickson/ateles repository, current default branch (markmhendrickson/ateles (GitHub, repository))
- Reproduction status
- Independently confirmed by Moona Intelligence through a direct shallow clone of the repository's current default branch and of pull request 807's own branch, reading agent_loader.py, grant_checker.py, skill_runner.py, mcp_tool_grant_proxy/proxy.py, validate_tool_allowlist.py, docs/architecture.md and docs/aauth.md directly. No credentialed access to the swarm's own production Neotoma instance exists for this entry, so the issue's own headline count, thirty one grant entities with zero tool capabilities across forty measured agents, is carried as issue reported evidence, not independently reproduced by this entry.
- Evidence state
- Confirmed
Known unknowns
- Whether the thirty one grant, forty agent, zero parity count remains accurate as of any date after the issue's own measurement, since neither this entry nor pull request 807's own verification pass could reach the production Neotoma endpoint.
- Whether any dispatch has actually exercised the widened Neotoma reach this entry confirms is available, as distinct from the reach being available.
- Whether decision 42's own full text states requirements beyond the derivation or parity rule the issue and the pull request both describe, since this entry could not read decision 42 directly.
Limitations
- This entry's access to markmhendrickson/ateles is limited to its public repository, read through unauthenticated git clones of specific branches. It has no access to the swarm's own production Neotoma database, its dispatch logs, or any live agent session.
- This entry read the exact source functions and command construction directly, but did not execute skill_runner.py's own dispatch path end to end, since doing so would require the swarm's own runtime environment and credentials this entry does not hold.
Claim provenance
- verified
Fetched directly on 7 September 2026. Confirmed opened the same day, open, carrying the label lanius triage, no comments, and stating the two disconnected representations, the reported thirty one grant, forty agent, zero parity count, and the request for a decision 86 dependent parity test.
The Harness Kept Its Own List of What an Agent Could Call. Nothing Ever Checked It Against the Grant. - verified
Downloaded directly through a shallow git clone of the repository's current default branch. Confirmed AgentDefinition.tool_allowlist and its own tools property in agent_loader.py, AgentGrant._parse's tool_grants construction in grant_checker.py, the unconditional mcp__mcpsrv_neotoma__* append and the per provider command construction in skill_runner.py, the permissive fail open docstring and the zero outside references for mcp_tool_grant_proxy/proxy.py, validate_tool_allowlist.py's own four recognized forms with no agent_grant reference, and docs/architecture.md and docs/aauth.md each describing the proxy as shipped and live.
The Harness Kept Its Own List of What an Agent Could Call. Nothing Ever Checked It Against the Grant. - verified
Fetched directly and independently cloned at its own branch, docs/register-decision-86-tool-grant-grammar, commit aea170e557fdc40117f563988ba0c1824a87f822. Confirmed open, design only, targeting another unmerged branch, and confirmed its own added docs/tool_grant_grammar.md states the same unconditional wildcard append and unwired proxy this entry independently found, plus its own five failed attempts, each returning a 502, to reverify the issue's own headline count against the production Neotoma endpoint.
The Harness Kept Its Own List of What an Agent Could Call. Nothing Ever Checked It Against the Grant.
