cd /news/ai-agents/ai-foundations-and-good-practices-cr… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-128299] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=↑ positive

AI - Foundations and good practices creating skills

A developer has compiled a set of best practices for defining skills for AI agents, drawing on an online workshop by @mouredev and additional research. The guide covers skill directory conventions such as ./.agents/skills and ./.claude/skills, required SKILL.md files, and YAML header fields including name, description, license, version, and context. It emphasizes precise, structured skill definitions to minimize model hallucination and warns that loading skills into session context should be controlled.

by read28 min views4 publishedSep 13, 2026

Let's talk about skills for AI agents, and we're doing it off the back of attending an online workshop given by @mouredev on skills a few days ago.

The workshop was really interesting, so much so that I was left wanting more, so I went digging a bit deeper, not so much into what skills do or what they're for, but into the best practices for defining them.

The result is this post, where I try to organize the main ideas I've been gathering and putting in order. I hope they're as useful to you as they've been to me.

Without further ado... let's get started.

Skills are used to automate repetitive processes whose procedure can be described with a high degree of precision.

The information inside a skill has to be perfectly structured and fine-tuned so that the model has the least possible chance of making up results.

The content of a skill can include:

When we start up an agent, it already knows which skills are available; however, skills can be invoked manually by the developer (explicit invocation), or automatically by the agent itself (** implicit invocation**), once we've made it aware that they exist.

Every skill we use gets loaded into the context of the current session, so it's important to control excessive use when they're not needed.

We'll create skills inside the ./.agents/skills directory (if they're only for the current project), or in ~/.agents/skills (if they're global for every agent running on the machine).

πŸ”Ž NOTE

This is the standard across the vast majority of agents, but just in case, it's always worth checking how a specific agent handles skills.

For example, in Claude Code CLI, if we manually create a skill in our repo, it won't be detected even after restarting the agent. Why? Because for this agent they need to be created in ./.claude/skills. It's not a problem with the skill or its definition, but with where Claude Code looks for it.

Each skill must be created inside a directory specific to that skill. Therefore, it's essential that the skill's directory name matches the name we give the skill itself, since that's the name by which the agent will invoke it.

On top of that, a SKILL.md file β€” containing the skill's definition β€” must always exist inside that directory.

Every skill must have a header that describes it. This header is identified by the opening and closing --- characters typical of YAML.

⚠️ IMPORTANT

Even though the skill is defined using Markdown, the content of the skill's header must be written in YAML.

The content of that header must include the following fields:

name Must be between 1 and 64 alphanumeric characters, lowercase, in kebab-case format.

It cannot start or end with a hyphen, and it can never contain two or more consecutive hyphens (--).

Finally, it must match the name of the directory where the skill is defined, since that's what's used to invoke the skill (/skill-name).

The regex for this name is: ^[a-z0-9]+(-[a-z0-9]+)*$.

description Must be between 1 and 1024 characters.

It has to be specific enough for the agent to be able to read its content and determine whether it matches what the user is looking for.

To do that, the description should contain specific phrases, verbs, or concrete use cases, for example: Use when the user asks to review code or optimize database queries.

license Used to define the legal usage context of the skill or its usage permissions.

When setting its value, it's considered good practice to follow the SPDX (Short-form License Identifiers) standard.

The most common values tend to be: MIT, Apache-2.0, GLP-3.0, and Proprietary or Commercial.

version Contains the string that defines the semantic versioning of the skill, for example: 1.0.0.

It's usually used to configure pipelines, deployment updates, or tracking within certain ecosystems.

context`` inline | fork Lets us define how the skill runs in relation to the agent's main conversation thread.

This aspect matters at the level of memory orchestration configuration and environment isolation when the skill is invoked.

By default, if this field isn't defined, the skill runs in line with the ongoing conversation; however, there are values we can assign to this field to change that behavior:

inline (default value)

The skill runs directly within the current conversation window.

The instructions, examples, and tools defined inside SKILL.md are added directly to the current context, and the model retains them in full for use in later parts of the conversation.

This setting is recommended when, upon starting multiple tasks that need to work together, the skill needs to know the entire history, tone, and specific references the user has made in order to operate correctly.

With all that said, if we choose this option, we need to set guardrails at the description level so the skill knows exactly when it should step back to gather information and then return to where it left off.

fork (sub-agent or isolated sandbox mode)

In this mode, you could think of it as creating a metaphorical "child process," where the agent temporarily s the main conversation thread, copies the relevant information from the current state, and spins up an isolated sub-agent to process exclusively the task assigned by the skill.

At the memory level, the sub-agent created doesn't read the entire memory or history of the main conversation; instead, it prevents the model from getting distracted from that conversation by avoiding drift caused by mixing in other queries.

At the token consumption level, since it doesn't take the full main conversation history but rather a small, very specific section, we can reduce the volume of input tokens and get a cheaper, faster execution.

Once the skill has completed its task, it gathers, cleans up, and distills a summary of the result and injects it into the main conversation thread before closing the "child process" in which it was operating.

With all that said, if we choose this option, we need to be aware that the instructions must be fully self-contained, since the skill won't have access to the complete conversation history.

Comparison table

Feature / Behavior context: inline (Default) context: fork
Work area Main conversation window Isolated sub-agent
History visibility Full history preserved Hidden (or heavily restricted)
Token consumption High (grows with conversation length) Low (optimized for skill-specific data)
Output obtained Continuous as the conversation goes on A simple, structured summary
Main use case Interactive assistant (e.g., copywriting) Heavy background work (e.g., code review)

compatibility This field acts as an environment check, making sure the machine where the skill or execution engine is running has the hardware capabilities, software packages, or required LLM engine requirements needed to run the instructions defined inside the skill. For example, we can define the model's minimum reasoning requirements, as well as operating system constraints, CLI packages, or required binaries.

If the system scans the skill and detects a compatibility issue, the skill is disabled or hidden to prevent runtime errors.

For example:

  compatibility:
    model: ">=gpt-4o"
    os: "linux, darwin"
    dependencies:
      - "python>=3.10"
      - "ffmpeg"

allowed-tools`` allow-tools) This field is defined by a list of values that strictly establish or limit which tools the agent is allowed to use when the skill runs.

When defining the content of this property, you should keep the Principle of Least Privilege in mind, so that if a skill needs to read local documentation, it shouldn't be allowed to execute terminal commands.

When a skill that has this property defined is executed, the agent automatically suspends/disables any tool not specified in the list, so that even if the model hallucinated and tried to invoke one of the disallowed tools, the model's orchestrator would block it.

One of the main advantages of this field is that it prevents excessive consumption caused by the unnecessary use of expensive tools or the execution of dangerous operations (files, databases, infrastructure, etc.) that aren't clearly authorized.

  allowed-tools:
    - internet_browse
    - read_local_file
    - parse_json

disable-model-invocation`` true | false This field is used to configure the level of "awareness" the model has about whether the skill in question exists or not.

When this field isn't defined, or is left at its default value (false), when the agent starts up it will have the skill in its list of available skills, and if the user says Check my server logs, the model will analyze the skill's description and, if it matches the goal of the request, it will start running the skill.

If this option is set to true, the model will completely ignore this skill, no matter how the agent is being used. The only way to use it is through explicit invocation of that skill, i.e., /skill-name.

This setting is particularly useful for destructive workflows, ones that apply irreversible changes, or ones that carry high risk for the system, where a misinterpretation by the model could lead to accidental loss of valuable data or unauthorized system changes.

  name: wipe-database-cache
  disable-model-invocation: true

metadata This field is an unstructured dictionary designed for development-specific tasks, where we can add additional information related to the skill.

It acts as a communication bridge between different platforms, code editors, and frameworks that need a way to define additional information relevant to each one, without breaking the open standard for skill definitions.

One of the main uses given to this field is to display the skill's information in a human-friendly format in applications or tools that manage skills.

On the other hand, when skills aren't public, this field can be used for tracking their development at a corporate level.

  metadata:
    author: "Platform Security Team"
    category: "DevOps / SRE"
    icon: "shield-alert"
    cost_center: "fintech-ops-99"

Some complete examples of skill headers could be the following:

---
name: kubernetes-manifest-validator
description: Use this skill when the user provides Kubernetes YAML files, Helm charts, or K8s deployment manifests and requests syntax validation, security linting, or API deprecation checks.
license: Apache-2.0
version: 2.4.1
context: fork
compatibility:
  model: ">=gpt-4o"
  os: "linux"
  dependencies:
    - "kubeconform>=0.6.0"
    - "trivy>=0.45.0"
allowed-tools:
  - read_local_file
  - execute_terminal_command
  - write_local_file
disable-model-invocation: false
metadata:
  team: "SRE-Core"
  environment: "staging-validation"
  severity-tier: "medium"
---
---
name: market-competitor-analyzer
description: Use this skill when the user asks for competitive intelligence, financial market trends, stock ticker comparisons, or landscape analysis regarding corporate competitors.
license: MIT
version: 1.0.3
context: inline
compatibility:
  model: ">=gpt-4-mini"
  os: "any"
  dependencies:
    - "python-yfinance>=0.2.0"
allowed-tools:
  - web_search
  - fetch_url_content
  - render_data_chart
disable-model-invocation: false
metadata:
  department: "Product-Strategy"
  billing-code: "mkt-res-2026"
  ux-icon: "trending-up"
---
---
name: production-database-purger
description: Mandatorily hidden from automatic routing. This skill safely drops stale tables, truncates high-volume log schemas, and runs database vacuuming routines on production clusters during maintenance windows.
license: Proprietary
version: 4.0.0-rc1
context: fork
compatibility:
  model: ">=o1-preview"
  os: "linux, darwin"
  dependencies:
    - "postgresql-client-16"
    - "aws-cli-v2"
allowed-tools:
  - execute_sql_query
  - fetch_vault_secret
disable-model-invocation: true
metadata:
  compliance-required: "SOC2-Type-II"
  requires-human-approval: true
  criticality: "high"
  slack-alert-channel: "#prod-ops-logs"
---

At this point, it's worth noting that even though these fields may belong to a standard, not every agent understands them or uses the same naming to achieve the same goal. The following table shows which agent accepts which header field:

Header fields for SKILL.md supported by agent

Header Field Claude Code CLI Claude.ai (Web) Claude API AutoGen Studio CrewAI Core LangGraph Engine OpenCode CLI Aider CLI CodeRabbit CLI
name βœ… βœ… βœ… βœ… βœ… βœ… βœ… βœ… βœ…
description βœ… βœ… βœ… βœ… βœ… βœ… βœ… βœ… βœ…
version βœ… ❌ βœ… ❌ βœ… βœ… βœ… ❌ βœ…
license βœ… ❌ βœ… ❌ ❌ ❌ ❌ ❌ βœ…
context βœ… ❌ βœ… ❌ ❌ ❌ βœ… (mode) ❌ βœ…
allowed-tools βœ… ❌ βœ… βœ… βœ… βœ… βœ… (perms) βœ… βœ…
disable-model-invocation βœ… ❌ βœ… ❌ ❌ ❌ βœ… (disable) ❌ βœ…
compatibility βœ… ❌ βœ… ❌ ❌ ❌ βœ… (deps) ❌ ❌
metadata βœ… βœ… βœ… βœ… βœ… βœ… βœ… βœ… βœ…

T-I-P-O Once we've finished defining the skill's header, it's time for the body.

⚠️ IMPORTANT

Unlike the header section, the body of a skill is written using Markdown.

What we define here is a compendium of semantic directives, structured in a certain way, that the model is able to internalize as operational instructions.

This block is decisive for whether the agent behaves as deterministically as possible, or starts having critical hallucinations during execution.

Despite the importance of this block, since it's open source, there's no single, strict structure that universally forces us to define a skill's body in a particular way. That said, in enterprise environments there's a growing convergence toward using the pattern known as T-I-P-O ( Targets, Inputs, Procedure, and Outputs), which is the de facto minimum accepted to guarantee a baseline of determinism in the model.

# Target (or # Objective) Defines what this skill's execution is aiming for and what the expected final goal is.

When an agent gets lost in a loop of tool calls, it re-evaluates its progress by comparing it against what's defined in this section.

Example:


  The absolute objective of this skill is to locate deprecated API endpoints inside the repository, upgrade them to the current SDK version, and ensure the test suite passes with zero errors.

# Inputs (or # Prerequisites) Defines the exact variables, files, or data formats the agent must receive before starting work.

This section matters because it stops the agent from "guessing" or making up data; that way, if the current context doesn't contain these elements, the agent knows it should stop and ask for them.


  This skill requires two primary artifacts from the active workspace context:

  1. `legacy_endpoints.json` - A manifest listing the raw endpoints.
  2. `current_sdk_spec.yaml` - The up-to-date OpenAPI schema reference.

# Procedure (or # Execution Steps) Defines a numbered, sequential list that the agent must follow strictly, step by step.

With this, we manage to break the model's reasoning down into manageable subtasks (Chain-of-Thought) while forcing the agent to follow numbered steps, reducing possible hallucinations in workflows that use multiple tools.


  1. Parse the `legacy_endpoints.json` file using the `read_file` tool.
  2. For each endpoint listed, locate its definition in the codebase using `grep_search`.
  3. Replace the deprecated syntax with the new methods specified in `current_sdk_spec.yaml`.
  4. Run the local testing pipeline using `execute_terminal_command(command="npm test")`.

# Outputs (or # Expected Output Format) Defines the output contract upon completion of the skill's execution.

Here we indicate whether we want a JSON, a Markdown document, a Markdown code block, etc., as well as the exact structure of the final response.

This way, the agent's outputs will be easily readable by other automated scripts or by the user, without containing filler text.


  Return exclusively a valid JSON block containing the compilation summary. Do not include conversational preambles.

Full example of a defined skill:

---
name: api-migration-tool
description: Use when the user requests an automated upgrade of legacy API endpoints.
version: 1.0.0
context: fork
allowed-tools:
  - read_file
  - write_file
  - grep_search
  - execute_terminal_command
disable-model-invocation: false
---


Migrate deprecated microservice API routing schemas to the v2 standard.


- Workspace variable: `target_directory`
- Source config file: `api_routing.conf`


1. Scan the `target_directory` for any `.conf` files.
2. Cross-reference keys against the official version 2 documentation wrapper.
3. Apply the structural rewrites into a new temporary branch.
4. Validate the syntax integrity.


Provide a markdown table summarizing:

- The file paths modified.
- The original lines of code.
- The rewritten replacement chunks.

πŸ”Ž NOTE

As a final note regarding the body of a skill, when we're in a section where we implement an unordered list, we sometimes find that both the hyphen (-) and the asterisk (*) are used to mark a list item.

While it's true that, computationally, it makes no difference to the model, cleanliness and order matter here from a DevEx standpoint, so the use of the hyphen (-) is encouraged for unordered list items over any other character.

These are the basic sections a skill should have. Beyond these, if our application's needs require defining additional sections, we're free to do so as long as it helps fine-tune the skill's use even further.

Some additional sections beyond those proposed by the T-I-P-O pattern are the following:

# Guardrails & Safety Constraints Defines critical restrictions by listing absolute limits, forbidden behaviors, and areas the agent must never touch.

This is the main line of defense against data destruction or security breaches.


  - **NEVER** pass raw string variables directly into bash command lines without character escaping.
  - Do not modify or read any files inside the hidden `.git/` or `.vault/` internal directories.

# User Verification Gates Establishes human approval checkpoints, explicitly defining which specific actions must mandatorily halt the agent's autonomous flow to require visual "Ok" or manual confirmation from the user in the chat.


  - **Trigger:** Prior to executing any database truncation or dropping an index.
  - **Action:** Halt the script, render the specific SQL payload to the user, and ask: "Do you confirm the execution of this database migration? (y/n)".

# Escalation Protocols This section prevents the agent from getting stuck trying to solve problems that exceed its permission capabilities, instructing it on when to give up and hand the case off to a human user.


  - If a connection timeout error occurs more than 3 consecutive times on port 5432, halt automation.
  - Do not attempt to guess credentials. Output: `[CRITICAL] Network isolation detected. Escalating ticket to SRE team.`

# State Tracking & Memory Logging With this section we force the model to structure its thought process and internalize state changes in local variables before calling the next tool, solving memory loss in very long workflows.


  - Before modifying a file, open a `<state>` block to log the original file hash and line count.
  - Maintain a rolling list of modified assets in your tool call parameters to avoid circular file edits.

# Chain-of-Thought Auditing Here, what we do is force the agent to justify each action using specific XML tags (like <thought>) before invoking terminal commands, which makes debugging and auditing the agent's behavior far easier.


  - Every tool call must be preceded by a `<reasoning>` block containing:
    1. Why this tool is necessary now.
    2. The expected outcome of the invocation.

# Performance & Cost Optimization Here we can prevent the agent from uncontrollably consuming the API budget (or exhausting the context window), by regulating the amount of text it can read or write in a single iteration.


  - When parsing log files, use range parameters to inspect a maximum of 150 lines per tool call.
  - Avoid re-reading large context files if the content was already logged in the active scratchpad.

# Compliance & Regulatory Standards This section matters when we're working with certain data, since it ensures that the deliverables generated by the agent (such as source code or data reports) comply with strict legal or organizational regulations for the sector (SOC2, GDPR, ISO), or from the company itself.


  - All telemetry methods designed by this skill must completely sanitize PII (Personally Identifiable Information).
  - Ensure encryption-in-transit configurations use TLS 1.3 as a baseline.

# Workspace Clean-up & Idempotency With this property we can guarantee the hygiene of the local system, ensuring the agent deletes its temporary execution files and that, if the skill runs twice in a row, the result is identical without duplicating data.


  - Upon task completion or premature failure, execute an explicit cleanup step to delete `/tmp/cache_*.json`.
  - Design every code refactor to be completely idempotent; running the skill twice must yield zero changes on the second run.

# Corporate Style & Terminology Glossaries Here we can unify business terms and the agent's voice when it generates technical documentation, reports, or text responses aimed at end clients or company leadership.


  - Use the term "Client Workspace" instead of "Tenant Folder" across all markdown outputs.
  - Keep tone formal and highly concise; eliminate words like "obviously", "simply", or conversational expressions.

# Diagnostic & Telemetry Footprints This property injects digital signatures and standardized logs into Git commits or the headers of files created by the agent, to uniquely identify which changes were made by the AI and which version of the skill was used.


  - Append this precise signature at the end of every modified file header:
    `/* Automated optimization applied via agent-skill: db-optimizer (v2.4.1) */`

As we develop a skill, it can become increasingly complex, which makes our SKILL.md file practically unworkable due to the amount of information, instructions, examples, or similar content it can contain. The most likely result is:

The solution to this lies in a process called Skill Atomization, through which heavy logic, external resources, and referential examples are extracted from the skill, turning it into a declarative orchestrator, keeping the file's content under 50 or 100 lines of text. This makes the skill's initialization speed within the agent very high and increases the system's scalability through independent reference updates.

This atomization process is carried out through two actions: Rigorous structuring and Technical linking.

Rigorous structuring Inside the directory where we've defined the SKILL.md file, we start creating directories with semantically sensible names.

Inside each of those directories, we create the corresponding files that will hold the information we want to extract from the original skill.

The directory structure depends solely on the development team, but there is indeed a certain tendency to have certain established directories, which don't need to be implemented if our skill doesn't require them, but if we do, it's recommended to keep the same naming.

An example of rigorous structuring could be this:

  my-complex-agent-skill/
    β”œβ”€β”€ SKILL.md                 # (Required   ) Main file (Orchestrator and Frontmatter)
    β”œβ”€β”€ scripts/                 # (Optional   ) Executable code that offloads heavy logic from the LLM
    β”‚   └── optimize_matrix.py   #               Numerical computation/complex analysis script
    β”œβ”€β”€ assets/                  # (Optional   ) Static data and validation schemas
    β”‚   └── database_schema.json #               Reference database structure
    β”œβ”€β”€ references/              # (Optional   ) Style guides, manuals, or dense documentation
    β”‚   └── code_style_guide.md  #               Formatting rules the LLM only reads if needed
    └── examples/                # (Optional   ) Few-Shot Example library (user stories)
        β”œβ”€β”€ standard_case.md
        └── edge_case_timeout.md

Technical linking Now that we've extracted the excess information from our skill into independent sections of our directory structure, we need to link that content back inside the file that's left.

For this we'll use explicit relative paths to the content we want to reference. Agents are able to read these paths and, through the use of internal tools, can access the files on demand, only when the procedure section requires it.

With this:

To do this, there are two commonly used patterns: Direct relative link and Footnote reference link.

Direct relative link

Used for immediate dependencies the agent must always inspect before running a procedure.


This skill requires the project context infrastructure to match the configuration rules specified in the core [Database Architectural Reference Schema](./assets/database_schema.json).

Footnote reference link

Used for dependencies that are worth having linked but whose happens only in very specific situations, meaning the agent won't load these references into context unless absolutely necessary.

Beyond that, they're also often used in very long procedures, pushing references to the end of the file and keeping the main text free of clutter.


1. Pull the latest Docker manifest using the environment variables.
2. Build the staging container and verify the cluster health check endpoints.
3. In case the build triggers a pipeline schema violation, fetch the resolution steps immediately.


* If the server returns a 503 error, verify if your service mesh matches the internal corporate architecture layout.

---

Now then, how can we start externalizing a skill? Well, we can start by laying out the following steps:

1. Move scripts out of the prompt context (/scripts)

Since explaining to an agent in natural language the operations a script must carry out is complex and consumes tokens unnecessarily, we can create a scripting file in a language of our choice that performs that operation.

In the skill's header, within the allowed-tools section, we'll grant execution permission for the execute_terminal_command command and invoke our script from the skill's text.

  ---
  name: my-custom-skill
  description: ...
  allowed-tools:
    - execute_terminal_command
  ---


  1. Do not compute matrix variances manually. Instead, trigger the native optimization script:
    `execute_terminal_command(command="python3 ./scripts/optimize_matrix.py --path=.")`

2. Externalize the example library (/examples)

We need to be very careful with how we use the linked files in this section, since, generally speaking, because they contain extensive, concrete examples, they can take up a lot of space, raising both input and output token consumption if we misuse the examples.

Ideally, each example should be its own independent file, so that linking to it allows one or another depending on the agent's needs.


  Before formatting your final response, read and analyze the corresponding execution logs inside the example library based on the current workload:
  - For standard microservice queries, read [Standard Flow Case](./examples/standard_case.md).
  - For database connection timeouts, read [Timeout Recovery Case](./examples/edge_case_timeout.md).

3. Load documentation on demand (/references)

API documentation, procedures, etc., can saturate an agent's context very quickly, and on top of that, keeping it updated would also require modifying the skill's content.

If we extract that documentation into independent, isolated files, we can selectively load them only when needed.


  If a compilation error occurs due to typing differences, do not attempt to guess the syntax. Read the internal reference document [Type Definition Manual](./references/code_style_guide.md) before attempting a second patch rewrite.

disable-model-invocation: true on destructive or production skills (like deployments or database purges) to force the skill to only be activated via a slash command (/) typed by a person. βœ… Leverage metadata for governance: Use the metadata block systematically in corporate environments to record the owning team, cost center, and compliance identifiers (e.g., compliance: SOC2).

❌ Duplicate skill names: Using the same name field in different SKILL.md files within the repository, which causes collisions and makes the orchestrator ignore components at random.

❌ Create generic or ambiguous descriptions: Writing descriptions like description: "An AI assistant to help you write code". This causes the LLM to activate the skill constantly for common tasks, saturating the context window.

❌ Grant universal permissions out of laziness: Declaring wildcards for tools or including terminal execution tools (execute_terminal_command) in skills that only need to read data.

❌ Ignore version control: Leaving the version field static at 1.0.0 indefinitely, preventing CI/CD pipelines from verifying whether production agents are running the most recently validated behavior.

❌ Confuse the role of context: fork: Configuring a skill as context: inline when it needs to process thousands of lines of server logs, causing the main chat to fill up with noise and burn through the token budget.

❌ Omit the license field in shared skills: Leaving the license field empty in shared internal repositories, exposing development teams to intellectual property compliance issues.

Chain-of-Thought).-) for lists of constraints, inputs, or tools. Reserve asterisks (*) exclusively for bold (**) or italics ([Reference 1]: ./references/guide.md), keeping the main flow free of filler text. βœ… State negative constraints assertively: Dedicate an independent section to safety restrictions (# Guardrails & Safety Constraints) and write prohibitions in uppercase and imperative form (e.g., "NEVER run recursive deletes").

❌ Mix bullet styles within the same block: Randomly combining hyphens (-) and asterisks (*) within the same list, which can break context segmentation in certain parsing engines.

❌ Write instructions as free-form narrative prose: Writing the procedure as a long paragraph instead of a structured list. Models tend to skip secondary instructions when they're buried in dense blocks of text.

❌ Embed extensive source code within the instructions: Pasting complete Python or Bash scripts into the prompt body. This drastically degrades the model's attention and drives up execution costs.

❌ Assume the agent knows the current environment: Writing procedures without first defining the # Inputs section, causing the agent to try to guess file paths, variable names, or database environments.

❌ Use ambiguous or conditional language: Using phrases like "Please try to optimize the query if you think it is a good idea". Production agents require direct, deterministic instructions (e.g., "Analyze query latency using the EXPLAIN tool").

❌ Overload the skill with too many secondary goals: Trying to make a single SKILL.md file handle code analysis, cloud deployments, and database optimization simultaneously. If the scope grows, split it into independent skills.

# Error Handling detailing exactly what the agent should do if a tool returns an error, times out, or returns empty data./scripts and have the agent run it, processing only the output summary./examples directory and link to them on demand, avoiding saturating the agent's initial context../assets/, ./scripts/, or ./references/ inside your skills actually exist physically and aren't broken.Halt Conditions) 403 Unauthorized) or persistent network failures. Keep the skill's core under 100 configuration tokens: Design the main SKILL.md as a lightweight, minimalist conductor that delegates to external resources, guaranteeing ultra-fast startups and optimal memory consumption. βœ… Define project-level skills according to that project's needs: When a skill is used in isolated projects, it's not advisable to extract it for global consumption, since any agent would load it regardless of whether it needs it for that particular repository or not. We should only create global skills, or promote a local skill to global, when we're 100% certain that skill will be used by every project.

❌ Allow infinite retry loops: Omitting contingency instructions for failures, which causes the agent to try running the same faulty tool over and over in an infinite cycle that burns through your API budget.

❌ Hide system error messages: Instructing the model to ignore terminal failures (e.g., 2> /dev/null). If the agent masks errors, diagnosing anomalous behavior in production environments becomes impossible.

❌ Hardcode credentials, absolute paths, or secrets: Writing passwords, API tokens, or absolute paths like /Users/username/project in the body of the skill. This breaks the agent's portability across different systems and creates a critical security vulnerability.

❌ Blindly trust long-term context memory: Designing a procedure that depends on the agent remembering a piece of data provided at the start of the general chat, especially when operating in context: inline configurations.

❌ Validate changes using the production environment itself: Allowing a code refactoring skill to apply direct modifications to the main branch (main) without forcing the prior execution of the local unit test suite on an isolated branch.

❌ Update external scripts without updating the skill's manual: Modifying the input parameters of an automation script in ./scripts/ but forgetting to update the corresponding tool-calling rules in the body of the SKILL.md file, causing the agent to invoke commands with outdated syntax.

It's clear that if there's one thing that hasn't changed with AI's arrival in the world of development, it's that best practices are more necessary now than ever, and a clear sign of that is the special care we need to take when defining our skills.

I hope this content has been useful to you. If you have any questions, feel free to reach out to me. Here are my profiles on X, LinkedIn, and Github.

── more in #ai-agents 4 stories Β· sorted by recency
── more on @@mouredev 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/ai-foundations-and-g…] indexed:0 read:28min 2026-09-13 Β· β€”