Agent Skills in Practice: Designing and Implementing in Real-World Systems
I’m Denis Shokhirev, an enterprise AI architect based in Erlangen, 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
I’m Denis Shokhirev, an enterprise AI architect based in Erlangen, 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.
Turn your process into an AI system
Fixed price. Production quality. DACH B2B focus.