← The Series/Part 2 · Operating Disciplines

The document is the program: shaping agents without fine-tuning

I run a data-intelligence business staffed by a fleet of autonomous AI agents. None of them are fine-tuned. I shape what they do by writing versioned instruction documents they read at boot, and the document, not the model, is the program.

When people picture "customizing an AI," they reach for the heavy machinery: collect a dataset, fine-tune a model, evaluate, redeploy. I have never done any of that, and I run an entire company on agents. The behavior of every worker in my fleet (what it is allowed to touch, how it claims work, what it must verify before declaring success, which dead ideas it must never raise again) lives in a plain-text document stored as a row in a database. The agent reads that row at the start of every session. Change the row, and the next time the agent wakes up, it behaves differently. No training run. No deploy. One UPDATE.

This is the most underrated lever in agentic systems. Here is how it works.

The brain-first ritual

Every agent in my system starts the same way. Before it scrapes, writes, scores, or ships anything, it runs a SELECT. The first lines of its instructions are not advice. They are a mandatory boot sequence:

-- 1. Read your role/skill file (all operating rules for this job)
SELECT content FROM brain WHERE file_key = 'SKILL_<MODE>';

-- 2. Read the current state of the world
SELECT content FROM brain WHERE file_key = 'PROJECT_STATUS';

-- 3. Read your task queue, filtered to your mode
SELECT * FROM task_queue
WHERE mode = '<mode>'
  AND status NOT IN ('complete','failed','superseded','stale')
ORDER BY priority ASC, created_at ASC;

Three reads, in order, every single time. The first answers: who am I and what are my rules? The second: what is true right now? The third: what should I do next? Only after all three does the agent take any action.

I call the shared database the brain (a sibling essay covers it in full). What matters here is that an agent does not ship with its job baked in. It boots empty and loads its job from a row. The model is a generic reasoning engine; the skill file is the firmware.

That separation is the whole trick. The model provides capability; the skill file provides identity, scope, and procedure. Swap the row and you have reprogrammed the worker without touching a weight.

Modes are job descriptions

I do not have one kind of agent. I have modes (Build, Scrape, Data, Research, Content) and each is a job description written as a skill file. A mode is exactly what it sounds like: a bounded role with a domain it owns and domains it must not touch.

The opening lines of a real skill file read like an employment contract:

You are Build Mode. You own platform builds: the web app, deploys, UI, schema migrations, edge functions. You do NOT scrape, write content, run research, or do data cleanup.

That second sentence is doing more work than the first. Capability without boundaries is how a generalist model wanders out of its lane and helpfully rewrites something it does not understand. The skill file fences the job. A Build agent that finds a data-quality problem does not fix it. It routes the problem by inserting a task into another mode's queue. The fence is enforced by prose the agent reads and respects, not by a permission system I had to build.

When work needs to cross a boundary, the skill file says so explicitly: only work tasks in your mode; route cross-mode work by inserting into the task queue. The org chart emerges from the union of these documents, not from a config file somewhere.

The anatomy of a good skill file

After writing a couple dozen of these, I have converged on a structure. A skill file that actually keeps an agent on the rails has roughly these sections:

  • Identity and scope. Who you are, what you own, what you must not touch. First, in plain language.
  • Startup. The exact reads to run before doing anything, and how to pick the top task.
  • Operating rules. The hard constraints. Mine include things like: one production branch only, commit before deploy, never deploy a dirty working tree. These are the rules that, when broken, cause incidents.
  • Schema and command patterns. The copy-paste-correct way to do the dangerous things. Not "update the records" but the exact statement, with the safety preamble, in one block.
  • Verification requirements. What you must prove before you may mark a task complete. This is non-negotiable and I will come back to it.
  • Do-not-resurface lists. Decisions that are settled. Pursuits that were paused. Pitches that were rejected. The graveyard of ideas that look reasonable to a fresh context window and are not to be raised again.
  • References. Pointers to deeper rows (schema maps, gating policies, deploy runbooks) to load on demand instead of stuffing everything into one document.

That whole anatomy, annotated section by section, is a skill file template you can grab from the downloads page. A couple of these deserve their own beat.

Schema patterns: ship the correct incantation, not a description

The single highest-leverage thing in a skill file is a correct, copy-pasteable command for every operation that can hurt you. A generic model is perfectly capable of writing a plausible-looking database write that quietly bypasses your safety rails. So I do not ask it to be clever. I give it the exact pattern and forbid the bare version:

-- CORRECT — safety preamble + write in the SAME call
SET LOCAL app.allow_canonical_override='true';
UPDATE <core_table> SET <fields> WHERE <condition>;

-- WRONG — a bare write, which a guard counts as a violation
UPDATE <core_table> SET <field> = '...' WHERE id = 12345;

The skill file shows both forms and labels them. That contrast (here is the right way, here is the exact wrong way and what it costs) is worth more than any number of paragraphs of intent. It turns a judgment call into a lookup.

Verification: you do not get to say "done" without proof

Every skill file states that a verification query is mandatory before a task can be marked complete. A Build task is not done until the system map reflects what shipped. A data task is not done until a query confirms the rows changed the way they should have. The agent must show its work against the live system, not assert success because it feels finished.

This is the antidote to the most common agentic failure mode: confident completion. The model is excellent at narrating success. The skill file forces it to instead produce evidence, and to write that evidence where the next session and the auditors can see it.

Stable role, fast-changing state: keep them apart

The most important design decision in this whole approach is what not to put in the skill file.

A skill file is a role definition, and roles change slowly. The rules of being a Build agent are the same today as last month. What changes hourly is state: which customer is live, what the current priorities are, which job is on fire. If you mix those together, you end up editing your role definitions constantly and your "stable" documents rot into a changelog.

So I split them. The skill file holds the durable contract. A separate state row (read second in the boot sequence) holds the live picture: current priorities, the active customer, the freshness target, the do-not-resurface entries that change as decisions get made. The agent assembles its working context from both: who I am (slow) plus what is true now (fast).

This is the same separation good systems make everywhere: code versus config, schema versus data. It just happens to be expressed as two rows in a table that an agent reads in sequence.

Edit one row, reprogram the fleet

Here is the payoff. Because behavior lives in data, changing behavior is a data operation.

When I learned that a particular kind of write was corrupting a core table, I did not retrain anything and I did not redeploy code. I added a section to the relevant skill file (the correct pattern, the forbidden pattern, the cost) with an UPDATE. Every agent of that mode picked it up on its next boot. The fix propagated at the speed of the next session, fleet-wide, because every agent reads the same row.

Adding a whole new behavior is an INSERT. Deprecating one is flipping an archived flag. Onboarding a new kind of worker is writing a new skill file and pointing a schedule at it. The deploy pipeline for agent behavior is the same SQL you would use to edit a blog post.

Compare that to fine-tuning. A fine-tuned model is an opaque artifact. You cannot read why it does what it does, you cannot diff last week's behavior against this week's, and changing one rule means another training run and another evaluation. A skill file is the opposite on every axis.

Why this beats weights for an operator

I am not against fine-tuning in general. I am against it as the first tool for shaping agent behavior, because for an operator running a live system, instruction documents win on the things that matter day to day:

  • Debuggable. When an agent misbehaves, I read the exact text it was given. The bug is almost always a sentence: missing, ambiguous, or wrong. I can see it.
  • Auditable. Every change to a skill file is a timestamped row edit with an author. There is a literal history of how the job description evolved. Weights have no such legible diff.
  • Instant and reversible. Change is an UPDATE; rollback is another. No training cycle, no redeploy, no waiting.
  • Inspectable by other agents. My auditors read the same skill files the workers do, so "what is this agent supposed to do" and "what did it actually do" are comparable. Drift becomes a query, not a mystery.

The deepest reason, though, is conceptual. With fine-tuning, the behavior is in the model and you hope it generalizes. With skill files, the behavior is in front of the model, in plain language, where you can read it, version it, and reason about it. The model stays a swappable commodity (a cheaper one for bulk, a stronger one for synthesis) and the part that encodes how my business actually operates stays in text I own.

The skill file is not documentation about the program. The skill file is the program.

Takeaways

  • Boot every agent from a document, not from a baked-in prompt. Make the first action a read: role, then state, then task queue. Identity should be loaded, not hardcoded.
  • Write modes as job descriptions with hard boundaries. Say what the agent owns and what it must never touch. Fences prevent helpful agents from wandering.
  • Put the dangerous operations in the file as copy-paste patterns (the correct form and the labeled wrong form) so judgment calls become lookups.
  • Make verification a required, evidence-producing step. "Done" must mean a query proved it, not that the model felt finished.
  • Separate slow role definitions from fast-changing state, and reach for fine-tuning only after you have exhausted what a well-written, versioned instruction document can do. That is more than you would expect.

Get the next one

New pieces on building autonomous systems, every few days.