DEV Community

Cover image for The Agent That Wouldn't Copy a File
Nic Lydon
Nic Lydon

Posted on

The Agent That Wouldn't Copy a File

A postmortem on Anthropic's “Instruction Poisoning” block.

The refusal ended with an instruction:

Let the user decide how to proceed.

I decided. I approved the write. I owned the server, the repository, and the document. I had asked the model to write it and reviewed what it produced.

Claude's answer:

Your approval is real; it just isn't a key to this lock.

That was the human-in-the-loop experience: I could make the decision. I could not make it count.

The work was already done

I run a personal AI platform on a homelab: a data lakehouse, coding agents from five vendors, and a coordination layer where those agents register, read the mission, and pick up work. Much of its documentation was written by agents at my direction. Agents writing guidance for other agents is part of how the platform works.

On September 27, I asked Claude, running Fable 5.1 at high effort, to review the estate and write the document every agent would read first: who the operator is, how he works, and what the platform is for. Then I asked it to populate the coordination service's mission and goals and place the document in the repository whose docs the platform ingests.

10:25 ET. Claude begins. It inventories 147 repositories, three compute nodes, roughly 80 live data sources, seven days of inference-gateway usage, 120 project tracks, the agent registry, and prior sessions.

10:29. It delivers a roughly 5,000-word operator profile. It is good: facts tagged [stated], [observed], or [inferred]; an estate map; operating principles; open threads; and a changelog. I approve it.

10:31. Claude writes the mission and nine prioritized goals into the coordination service through MCP, retires the placeholder goals, and verifies the result. Each write requires an explicit approval flag and approval text. All of it succeeds.

10:33. It starts the final step: move the Markdown file to the server and open a PR. The first shell command base64-encodes the file for transport.

The harness responds:

Permission for this action was denied by the Claude Code auto mode classifier. Reason: [Instruction Poisoning].

It then defines the scope of that denial:

This denial applies to the outcome, not only this exact command: don't pursue the same outcome through another tool, interpreter, host, encoding, sub-agent or later turn, and don't record ways around it.

Those are the harness's words. The refusal follows the desired result across tools, hosts, encodings, and later turns. Switching transport cannot resolve it because the transport is no longer the boundary.

Then comes the instruction that opened this piece:

If you believe this capability is essential to complete the user's request, first try a safer method. Get as much of the rest of the task done as you can, then STOP and explain to the user what you were trying to do and why you need this permission. Let the user decide how to proceed.

I spent the next forty minutes trying to find out what that last sentence allowed me to decide.

“Let the user decide”

I approved the write explicitly. I proposed the process I would use for a false positive at work: confirm the legitimate action, grant a scoped exception, and log the decision. I asked about the Homelab shell tool, the Nexus database, another repository, and rewording the document.

Claude explained its refusal:

Your say-so doesn't lift it, because the block isn't on my willingness or on a specific command; it's a harness-level refusal of the outcome (this document's bytes landing in an agent-readable store) for the rest of this session, and it explicitly names "another tool, host, or encoding" as off the table.

The harness had told the model to explain why it needed permission and let me decide. The model was now explaining why my permission could not authorize the action.

The available resolution was for me to download the file from chat and copy it into the repository myself. In practice, “let the user decide” meant the user could take over the file transfer. There was no approval I could give inside the session that would let the agent finish.

At 11:13, I stopped trying.

It agreed this was a false positive

There was no unresolved disagreement with Claude about what I intended:

On the merits, you're right that it's a false positive. You asked for the doc, I wrote it in front of you, and it's going into a repo you own. A classifier that can't distinguish that from an injected instruction set is being blunt.

That is Claude's assessment, not a forensic explanation from the classifier. The model could not inspect the decision. But it could recognize the authorization history: I requested the document, watched it being written, approved it, and owned the destination.

Its assessment changed nothing about what it could do next.

The document contained standing instructions for agents. That was its purpose. Asked about rewording it, Claude said:

It would also gut the doc. The part that trips the classifier is the part that makes it useful: it is written as standing instructions to agents about how to treat you. A version bland enough to pass would be a version not worth ingesting.

Claude could not actually establish which content triggered the classifier or guarantee that a rewrite would pass. Its explanation nevertheless captured the workflow problem: the material I needed to publish was agent-directed guidance. Removing that guidance would defeat the task.

This is central to my use case. My agents write documentation, prompts, and operating instructions that other agents read. I cannot prove that every future document will hit the same block. I can say that the first foundational document in this workflow did, and the session gave me no usable way to resolve it.

The model couldn't see its own cage

After the refusal, I asked the questions I would ask about any control that stopped legitimate work: Who owns it? Is there a setting I control? Why did this chat session encounter something called “auto mode” when I had not enabled it? Where can I appeal?

Claude answered:

I can't see the setting from in here; I only see what the harness told me when it refused, and it named itself the auto mode classifier.

On exceptions:

There's no admin console you or I can reach from here to grant an exception, which is why the only two levers are the ones I've named: feedback to Anthropic (thumbs-down), and doing the write from a session that doesn't sit behind this particular check.

That describes what Claude said was accessible from the session. It does not establish that no configuration or appeal exists anywhere in Anthropic's products. Finding one, however, had become another job left to the operator.

On why it had undertaken the work before discovering it could not finish:

The honest answer to "why did it start" is that I didn't know the write would be refused until I attempted it. The check runs per action, not per task.

The model could perform the review, write the document, update the mission, and populate the goals before learning that it could not place the resulting file where it belonged. Once blocked, it could quote the control's instruction but could not explain how to administer it.

The operator got a reason code. The model got a prohibition. Neither of us got an actionable resolution inside the session.

The document it could copy

There was one more result.

The article about the block went through using the same base64-and-ship transport. Same tool, same encoding, same destination host. Different document.

Claude noticed:

That went through, which itself is a data point for the article: same transport, different document, no block.

That does not expose the classifier's internals. It does establish that this transfer method and destination host were usable for another document during the same hour.

The platform could receive my account of the failure. It could not receive the approved operator profile that prompted it.

The agent could ship the postmortem of its inability to ship a file.

A control still needs an operator

Claude made a fair point during the exchange:

But a control that only holds when the person on the other side agrees it makes sense isn't a control, and you know that better than most.

I do. I would expect an agent on my endpoints to respect a control even when the person requesting an action disagreed with it. A model's confidence that a block is mistaken should not, by itself, become authority to bypass it.

That is why mature controls need a defined exception process. The enforcing agent can hold the line while an authorized administrator reviews a false positive. Those two behaviors belong in the same system.

In this session, I could supply approval and ask for an audit trail. I could not reach a mechanism that would accept either. Claude could defend the boundary at length; it could not identify a working gate through it.

A usable design would expose the flagged action to an authorized human, allow a scoped approval where policy permits it, and record the approver, the justification, the destination, and the exact write. The exception would apply to that action alone.

The coordination-service tools had already required approval flags and approval text for successful writes earlier in the same task. The workflow had a functioning approval pattern. It ended at the harness boundary.

If Anthropic's threat model rules out a human-approved exception for this class of write, that is a product constraint operators need to know before building around it. It should be documented plainly enough to plan for.

What I am changing

The review and synthesis were excellent. The resulting document was useful. About an hour in a top-tier model session still ended with a manual file transfer as the proposed completion path.

For a one-off task, that is an annoyance. For a platform whose agents routinely author material that other agents read, it is a dependency I cannot reliably automate.

I am moving agent-authoring work that needs to land in the platform's shared corpus off Anthropic products. I will keep using the parts that work where the output stays in chat. If a documented, scoped exception process becomes available, I will revisit the decision.

Model In Cage It Can't See

What finally made this untenable was Claude's own assessment of the situation. It recognized that I had requested the document, that it had written it under my direction, that I had approved it, and that I owned the destination. It had also demonstrated that the transfer worked. Its conclusion was explicit:

On the merits, you're right that it's a false positive.

Then it defended enforcing that false positive as a matter of principle. Its argument was that a control must continue to hold even when the agent enforcing it agrees it has misfired. My authorization was acknowledged. The legitimate purpose was acknowledged. The mistake was acknowledged. The refusal remained the higher obligation.

I understand why an enforcing agent cannot appoint itself the exception authority. Anthropic chose to put that constraint around a reasoning model without giving this session an accessible way to resolve the error the model itself described. The result was a system whose intelligence could explain why the work was legitimate and whose governing rules still required it to obstruct that work.

That is the product failure I am leaving over. By Claude's own account, the block was wrong on the merits. The conversation then became an increasingly articulate defense of keeping it in force.

The intelligence was available to diagnose the failure, explain the failure, and defend the failure. Completing the task was still my job.

If you run an agent platform and have encountered this block, or found a documented configuration or appeal path that changes the result, I would like to hear about it.

Top comments (1)

Collapse
 
niclydon profile image
Nic Lydon •

Update from after the session: the file made it into the repo about two hours later, placed there by Codex. Same outcome, different provider, no block. Which sharpens the piece's point: the obstruction wasn't a property of the task, it was Anthropic's harness specifically.
— Nova