The difference between a skill and an agent, in one sentence
A skill is something you invoke. An agent is something that decides.
That is the whole difference, and it is enormous. When you write a skill you fix the steps in advance: take input, do A, do B, return output. The model fills in a template. An agent has no template. It has a goal, a set of tools, and a loop. The model picks the next step itself, based on what it saw in the previous one. You are not writing the script. You are writing the conditions under which the script gets written.
And because that sounds exciting, people rush to build agents when they do not need one. My rule is simple: if you can write the steps on a piece of paper before the run starts, it is a skill. If step three depends on what happens in step two, only then is it an agent. Test yourself:
The loop: what actually happens on every turn
Every agent, however elaborate, runs the same four-step loop: it perceives the current context, decides what to do, acts through a tool, and observes the result. The result goes back into context, and the loop starts again. That is it. There is no magic beyond that.
Here is the part that matters: the model makes a decision once per turn, in the "decide" step. Everything else is plumbing you wrote. The quality of the agent is set by what the model sees at that moment: which tools are offered, how they are described, and what survived in context from earlier turns.
Step through the run below turn by turn. Then switch to "watch it break" - the exact same task, with one tool that is described badly. Notice the precise turn where things start to slide, and what happens to the context meter:
What you see in the broken run is not "the model is stupid". It is that one bad first decision contaminated the context, and every decision after it was made on contaminated context. In agents, mistakes do not get replaced. They accumulate.
Tools: what to hand over and what to hold back
The instinct is to give the agent everything: search, files, terminal, browser, twenty tools, let it figure it out. In practice every extra tool is one more opportunity for a wrong choice. I have watched an agent with 4 sharp tools beat an agent with 15 general ones, over and over, on exactly the same tasks.
And the part everyone misses: the tool description is the real interface. Not its code. The model never sees the implementation. It sees a name, a description, and parameters. A vague description produces vague choices. Try the three tasks against both descriptions:
This is what a description that works looks like. It says what the tool does, what it does not do, and what comes back from it:
{
"name": "code_search",
"description": "Searches ONLY this repo's source code.
Returns up to 20 matching lines with file paths.
NOT a web search - for docs use fetch_docs.",
"input": { "query": "string, a literal or regex pattern" }
}Those three words, "NOT a web search", are worth more than any prompt patch you write afterwards. Describe a tool the way you would brief a new hire on day one: short, sharp, and clear about the boundaries.
Memory and context: what survives between turns
The agent does not "remember". It has a context window, and everything that enters it stays there until the space runs out. Every tool result, every error, every failed attempt piles up. After 20 turns the context of a typical agent is 80% waste: stale outputs that no longer matter, crowding out the things that do.
This is what kills long-running agents, and it has a name: context rot. The original task was written on turn #1, and by turn #30 it is either out of the window entirely or buried under 40K tokens of logs. The agent keeps running, it just no longer remembers what for.
Three rules that work for me:
- Files, not context. Anything that has to survive gets written to a file (progress summary, decisions, what was tried and failed) and re-read at the start of each phase. Context is working memory, not an archive.
- Truncate results. A tool that returns 3,000 log lines should return the 30 relevant ones. The truncation belongs in the tool, not in the model.
- Repeat the task to itself. A short reminder of the goal and the stop condition gets injected every few turns, so it never falls out of the window.
Guardrails: what an agent never does alone
An agent without guardrails is not "autonomous", it is recklessness with an API key. Before you let anything run unsupervised, four things have to be in place: a turn ceiling, a token budget, a defined stop condition, and a human checkpoint on every irreversible action. Switch one off and see what it costs:
Notice the asymmetry: the turn ceiling and the budget save money and time. But human approval is the only one that prevents irreversible damage. Deleting, force push, sending a customer email, deploying - all of those stop and ask. Always. Even when the agent is "sure". Especially when the agent is sure.
A good stop condition is external and measurable, not a feeling the model has:
// stop when ALL of these hold - not when the model "feels done" stop_when: tests_pass: true // measured, not self-reported turns_used: "<= 15" tokens_used: "<= 50_000" destructive_actions: 0 // anything else requires approval
Evals and traces: judge the path, not the answer
With a skill you check the output: input goes in, output comes out, right or wrong. With an agent that is not enough. An agent can reach the right answer down a horrifying path (30 turns, two files deleted by accident and restored), or fail politely after a flawless one. What you need to judge is the trajectory: the sequence of decisions, not just the ending.
And because agents are not deterministic, a single run tells you nothing. I run the same task 10 times before any change: if 8 succeed and 2 get stuck in a loop, I have a stability problem, not a capability problem, and the fix is completely different.
The habit works outside agents too. When I wanted to know which backend was faster in my transcription tool, I let the numbers decide instead of guessing. The answer was 5.81x, and I would not have guessed it right.
The most valuable tool in the box is reading a trace. When a run fails, the answer is always at one specific turn - the turn where a reasonable-looking decision sent everything to the wrong place. Open this trace turn by turn and try to find it before you press the button:
Most people guess the failure is where the tests broke. It never is. It is always a few turns earlier, in a decision that looked sensible at the time. Reading traces is a skill, and the people who develop it fix agents ten times faster than the people who only look at the final answer.
That is the whole thing. A simple loop, a few sharp tools, context you manage, guardrails you do not compromise on, and judgement based on the path. An agent built that way is not perfect, but it works, and when it breaks you know exactly where.