Concepts / Defensive Prompt Engineering

Defensive Prompt Engineering

Prompt metadata is data about a prompt, such as model_name, date_created, prompt_text, application, and creator, that tells you what the prompt is for and lets you search for it.

  • Programming

Why a Bare Prompt String Is Not Enough

Imagine a team with one small project and one prompt sitting in one file. That arrangement is easy to manage. Now imagine the organization runs many prompts across several applications. Someone who finds a prompt string with no surrounding information cannot tell which model it was written for, when it was created, which application uses it, or who is responsible for it. Each of those unanswered questions has a practical cost when something goes wrong in production.

Defensive prompt engineering is the habit of attaching enough information to every prompt that its purpose, owner, and intended use can be recovered later, even after the original author has moved on. This article follows that idea from a single Python object up to the way teams manage whole collections of prompts over time.

Predicting What a Bare Prompt Cannot Answer

What do you think happens?

Given only the prompt text, which of these questions can you answer: which model it was written for, when it was created, which application uses it, or who is responsible for it?

  • Only the first one

  • None of them

  • All of them

  • Only the question about who is responsible

Reveal answer
Answer:

None of them

A prompt string with no surrounding information cannot tell you which model it was written for, when it was created, which application uses it, or who is responsible for it. The answers have to be stored alongside the text as metadata.

Metadata as Labels on a Prompt

Definition

Prompt metadata is data about a prompt rather than the prompt's own words. Metadata such as model_name, date_created, prompt_text, application, and creator tells you what the prompt is for, and it lets you search for it.

The five fields work together. The prompt_text field holds the words the model receives. The model_name field records which model the prompt was written for. The date_created field records when it was made. The application field names the program that uses it, and the creator field names the person or group responsible for it. Good metadata lets you answer the question what is this prompt for, and it also lets you organize prompts so you can search for them by model, by application, and by other attributes.

Bundling Text and Metadata in One Object

One way to attach metadata is to wrap each prompt in a Python object. The object holds the prompt text next to the fields that describe it. The class below uses Pydantic's BaseModel, which lets you declare the type of each field. Read the field names first and try to say, in your own words, what each one records.

python
Notes on the code
  • The class declares each field and its type in one place
  • Each field is declared without a default value
  • The object keeps the prompt text and its description together as one unit

Each field has a declared type, and Pydantic uses those declarations to check values when a Prompt is created. That check is the main reason to use a model class instead of a plain dictionary. The structure of every prompt record is written down in one place, so a prompt that lacks a field is caught at creation time rather than discovered later during a search.

Prompt objectprompt_textthe words sent to the modelmodel_namethe model it was writtenfordate_createdwhen it was madeapplicationthe program that uses itcreatorwho is responsiblecontainscontainscontainscontainscontains
How the prompt text and its metadata fields relate as parts of a single Prompt unit

Predicting the Result of a Missing Field

What do you think happens?

If you create a Prompt without a creator field, when does the problem get noticed?

  • Immediately, when the Prompt object is created

  • Later, when someone searches for the prompt

  • Never, because the prompt text still works

Reveal answer
Answer:

Immediately, when the Prompt object is created

Every field is declared without a default value, so each one is required. Because the structure is checked at creation time, the missing field is caught then rather than discovered later during a search.

python
Notes on the code
  • Every field except creator is supplied
  • Creator has no default, so the class cannot build a complete record from these arguments

Tracing a Prompt Through Creation

Create Promptarguments passed to theclassmodel_name given?creator given?Object acceptedrecord is completeMissing fieldreportedcaught at creation timecheckyesnoyesno
The step-by-step path a Prompt takes from creation to acceptance or rejection, showing where the check branches
Worked example

Tracing the broken_prompt creation

Follow what happens when the Prompt object from the previous example is created without a creator value.

  1. 1
    Read the arguments

    prompt_text, model_name, date_created, and application are all supplied; creator is not.

  2. 2
    Check each declared field

    The class checks each declared field against the supplied values. The first three fields pass, and application passes.

  3. 3
    Reach the missing field

    creator is declared without a default, so there is no value to fall back on.

  4. 4
    Refuse to build the record

    The incomplete object is not accepted. The problem is reported at the line where the object is created.

Result

The prompt never enters the collection as a broken record. Had the class accepted it, the missing creator would have surfaced only when someone later searched for the prompt's owner.

Operational Details That Belong With the Prompt

The five identity and ownership fields are not the whole story. A prompt template may also carry operational details about how it should be used. The source describes three additional kinds of information that a template might contain.

  • The model endpoint URL, which identifies where the prompt is sent
  • Sampling parameters such as temperature or top-p, which control how the model chooses its output
  • The expected output schema for structured outputs, which describes the shape the response must take

These operational details belong with the prompt for the same reason the identity fields do. A prompt that expects a particular output structure is incomplete without a record of that expectation, and a prompt tuned with specific sampling settings behaves differently when those settings are lost. Keeping them in the same record as the text means the prompt carries what it needs to be used correctly.

Some tools have gone further and proposed dedicated file formats for storing prompts. The source names Google Firebase's Dotprompt, Humanloop, Continue Dev, and Promptfile. Whatever format a team picks, the goal is the same: the prompt and its metadata are stored together as one unit.

Versioning in Git Versus a Prompt Catalog

Metadata tells you what a prompt is. Versioning tells you which revision of the prompt a given application is running. If prompt files live inside your git repository, you can version them with git, just as you version the rest of your code. Every change to a prompt file becomes a commit, and the history of that file records how the prompt evolved.

The limitation appears when several applications share one prompt file. A shared prompt update forces every dependent application onto the new version. Many teams solve this shared-file problem with a separate prompt catalog, which is its own store of prompts, independent of any one application's code. The catalog explicitly versions each prompt, so different applications can pin themselves to different prompt versions. One application can stay on version one while another moves to version two, and neither decision forces the other.

Prompt file in repoSeparate prompt storeCommit historyeach change is a commitExplicit versioneach prompt versionedShared updateevery dependent app movesPinned perapplicationapps choose their versiontracked byleads toidentified byleads to
How a prompt version is stored, identified, and shared under git versus a separate prompt catalog
QuestionGit repositorySeparate prompt catalog
Where does the prompt live?Inside the application's repositoryIn its own store, independent of any one application's code
How is a version identified?By the history of commits to the prompt fileExplicitly, because the catalog versions each prompt
What happens when it changes?A shared update forces every dependent application onto the new versionApplications stay pinned to the versions they chose
How do owners learn of changes?Not described in the sourceA well-built catalog may notify application owners of a newer version
Can you search for prompts?Not a built-in capability described in the sourceYes, the catalog supports search and provides metadata

Git versioning compared with a separate prompt catalog

Spotting Divergence From Expectations

Suppose two applications were supposed to use the same summarization prompt, but one of them now produces output that looks different from what the team expected. The source suggests a method for finding where the divergence came from. Start from the record for each prompt and ask what the metadata says about the application, the model, and the creator. Then ask which version each application is actually using.

Worked example

Finding the source of a changed summary

Two applications share a summarization prompt. One now produces output that looks different from what the team expected. Where should the investigation start?

  1. 1
    Compare the application fields

    Check the application field on each prompt record to confirm which program uses which record.

  2. 2
    Compare the model names

    A difference in model_name between the two records is a strong lead, because the same text can behave differently on a different model.

  3. 3
    Check the pinned version

    Find which version each application is actually using. A difference in the version pinned by one application narrows the search quickly.

  4. 4
    Read the prompt text last

    Rereading the text is the slowest route. The metadata and version history often explain the difference before the wording needs to be examined.

Result

The divergence is traced to a metadata or version difference, such as a different model_name or a different pinned version, rather than to a guess about the prompt wording.

Mistakes That Undermine Prompt Traceability

  • Common mistake

    Storing the prompt text alone

    What it looks like

    A prompt string saved in a file with no model, date, application, or creator recorded

    Why it fails

    Nobody can tell which model it was written for, when it was created, which application uses it, or who is responsible

    Do this instead

    Store the prompt together with its metadata as one unit

  • Common mistake

    Using a plain dictionary and assuming every record is complete

    Why it fails

    A plain dictionary does not write the structure of each record in one place, so a missing field may go unnoticed until a search fails

    Do this instead

    Declare the fields in a model class so a missing field is caught at creation time

  • Common mistake

    Leaving out operational details

    What it looks like

    Saving the text but not the expected output schema or sampling settings

    Why it fails

    A prompt that expects a particular output structure or uses specific sampling settings behaves differently when those details are lost

    Do this instead

    Keep the endpoint URL, sampling parameters, and output schema in the same record

  • Common mistake

    Assuming a shared git file is safe for every application

    Why it fails

    A shared prompt update forces every dependent application onto the new version

    Do this instead

    Use a separate prompt catalog that lets applications pin different versions when they need to

  • Common mistake

    Rereading the prompt text first when output changes, instead of comparing metadata and pinned versions

Practice Tracing a Prompt Record

MEDIUM

A teammate creates a Prompt object for a translation prompt and supplies prompt_text, model_name, and creator, but leaves out date_created. Using the Prompt class from this article, predict whether the object is accepted, and explain which field is responsible and at what point the problem is caught. Then describe one metadata field you would compare first if the translation output later changed unexpectedly.

Hints
  • Recall that every field in the class is declared without a default value.
  • Think about when the class checks the declared fields, not when the prompt is later searched.
  • Consider which metadata field tells you which program uses the prompt, and which tells you which model it was written for.

Key Takeaways

  • Prompt metadata such as model_name, date_created, prompt_text, application, and creator records what a prompt is for and makes it searchable.
  • A Python model class holds the prompt text with its metadata and checks declared fields at creation time, so a missing required field is caught immediately rather than during a later search.
  • Versioning prompts in git ties every change to a commit, but a shared update forces every dependent application onto the new version; a separate prompt catalog versions each prompt explicitly so applications can pin different versions.
  • When output diverges from expectations, compare the metadata and pinned versions in each prompt record before rereading the prompt text.

Related concepts

More concepts starting with D