Agent Skills in Practice: Designing and Implementing in Real-World Systems
I’m Denis Shokhirev, an enterprise AI architect based in Freiburg, Germany, running DennisCraft AI Studio. Over the past six months, I shipped 14 production AI agents for logistics and fintech clients in the DACH region. My core stack: Claude, Supabase, n8n, Doppler, and self-hosted Postgres. The main pain point I face isn’t model accuracy — it’s building agent “skills” that work reliably in regulated, rapidly-changing production setups.
What is an Agent Skill in Production?
In the real world, an agent skill isn’t just a prompt or a block of LLM code. It’s a pipeline composed of input validation, execution (often across APIs and databases), error handling, and clear output. For instance, a “generate invoice” skill must sanitize user input, trigger a Postgres insert, call an external billing API, and return a structured response. The biggest risk? Skills breaking when an upstream API changes or a schema drifts.
Designing Skills: Function Pattern, Not Prompt Pattern
Why “Prompt as Skill” Fails in Production
At hackathons, a new skill often means a new prompt. In production, I’ve seen this approach collapse. On three recent agent launches, prompt-based skills generated SQL with classic vulnerabilities (e.g., SQL injection, broken JOINs). My solution: treat every skill as a function — strict input/output schemas, business logic outside the LLM. The LLM is a parser or generator, not the executor of logic.
Concrete Example: Invoice Creation Skill
def create_invoice(payload: dict) -> dict:
if not validate_invoice(payload):
return {"error": "validation_failed"}
invoice_id = insert_into_pg(payload)
api_result = send_invoice(invoice_id)
return {"invoice_id": invoice_id, "api_status": api_result}
The LLM’s role: parsing unstructured requests or generating email text. All DB and API logic stays outside the model.
Skill Integration: Orchestrators and Supabase
Don’t Hardcode Skills in Agents
Hard-coded skills — directly embedded in the agent — don’t scale. Every change means redeploying the whole agent. I externalize each skill as a Supabase REST endpoint or an n8n node. This way, skills can evolve (or roll back) independently, and the agent’s core stays stable.
Orchestrating Skills with n8n
- id: create_invoice
type: httpRequest
properties:
url: https://api.denniscraft.ai/invoice
method: POST
- id: send_notification
type: emailSend
properties:
to: {{$json.client_email}}
subject: "Your Invoice"
n8n lets me chain skills and handle errors visually. Supabase handles skill schemas, access control, and versioning.
Skill Security: Static Analysis and Runtime Sandbox
What Breaks in Reality
I regularly catch LLM-generated code that would be a security nightmare if shipped raw. On three recent launches, prompt-based skills wrote unsafe SQL (missing parameterization, risking injection). I use semgrep and bandit for static code analysis, and gitleaks for secret scanning. For runtime, I sandbox skills: block all exec/eval, enforce timeouts, and log all external calls. The OpenAI cookbook’s “secure function calling” pattern is a good reference (openai.com).
| Tool | Purpose | Where Used |
|---|---|---|
| semgrep | Vulnerability pattern scan | CI/CD, pre-commit |
| bandit | Python code security scan | CI/CD |
| gitleaks | Secret detection in repo | Pre-push |
Versioning and Rollback for Skills
Every skill in production needs explicit versioning. In Supabase, I have a skills table with skill_id, version, schema, code_hash, and active_flag. A rollback is just a flag switch. Without this, a broken skill can cascade failures through your agent chain.
CREATE TABLE skills (
skill_id TEXT,
version INT,
schema JSONB,
code_hash TEXT,
active_flag BOOLEAN
);
FAQ
How do you test a new skill safely before pushing to prod?
I expose a test endpoint, run skills against prod-like (read-only) data in a sandboxed environment, and review logs. Manual code review is mandatory before rollout.
Should an LLM ever get direct CRUD access to your main DB?
Never. Always use a proxy layer with whitelisted functions. Even Claude writes a DROP when it should SELECT. LLMs parse/generate, not execute.
How do you hotfix a broken skill in production?
Keep a dedicated hotfix branch and a separate CI/CD pipeline to a test endpoint. After review, flip the active_flag in Supabase. Downtime is seconds.
What’s the minimum logging set for a skill?
user_id, skill_id, input/output (no PII), status, execution time, error trace. n8n makes it easy to write to a dedicated logs collection.
Can skills be described in openapi.yaml for codegen?
Yes, if the schema is strict and no “human in the loop” steps are required. This enables auto-test and validation.
Where in your skill pipeline do you see the most production failures — input validation, external API call, or result return? I’d genuinely like to compare notes. I run a free 30-min stack audit for DACH founders building AI in regulated markets. DM me on LinkedIn or write to @ger_dennis_ai.