hi @ShenghuZhang
skills are designed to be stateless instruction sets, not executable code that manages connections or transactions. Business transactions should be handled by tools (with dependency injection) or graph nodes (with runtime context), not by skills themselves.
Skills are stateless sorkflow Instructions - not executable business logic
According to the Deep Agents documentation and the Agent Skills specification, a skill is a directory containing a SKILL.md file with YAML frontmatter and Markdown instructions:
/skills/my-skill/
├── SKILL.md # Required: YAML frontmatter + markdown instructions
├── scripts/ # Optional: helper scripts
├── references/ # Optional: domain docs (e.g., DB schemas)
└── assets/ # Optional: templates
The SKILL.md is a prompt - it tells the agent how to approach a task, not how to connect to a database. Here’s a real example from the Deep Agents text-to-sql example
Notice that the skill references tools (sql_db_schema, sql_db_query) but doesn’t contain any connection logic, transaction management, or executable code that interacts with the database. The skill tells the agent what tools to use and in what order - the tools themselves handle the actual database interaction.
Skills also use progressive disclosure - the agent only loads a skill’s full content when it determines the skill is relevant. From the skills middleware source code (deepagents/middleware/skills.py):
“Skills are loaded from one or more sources… The middleware uses backend APIs exclusively (no direct filesystem access), making it portable across different storage backends.”
This means skills are treated as read-only context, not as running services with connections.
Tools are where business logic lives
The correct place for database connections, CRUD operations, and transaction management is in tools. Tools are executable functions that the agent calls to perform actions. In the text-to-sql example, the database connection is managed by the tool layer:
from langchain_community.utilities import SQLDatabase
from langchain_community.agent_toolkits import SQLDatabaseToolkit
db = SQLDatabase.from_uri(f"sqlite:///{db_path}")
toolkit = SQLDatabaseToolkit(db=db, llm=model)
sql_tools = toolkit.get_tools()
agent = create_deep_agent(
model=model,
tools=sql_tools, # DB tools handle connections
skills=["./skills/"], # Skills only provide workflow guidance
backend=FilesystemBackend(root_dir=base_dir),
)
Source: sources/deepagents/examples/text-to-sql-agent/agent.py
The SQLDatabase object manages the connection; the toolkit wraps it in tools like sql_db_query and sql_db_schema. The skill merely tells the agent when and how to call those tools.
For custom business transactions, use dependency injection in tools
If you need tools that perform business transactions (e.g., creating orders, updating records with commit/rollback), LangChain and LangGraph provide robust dependency injection mechanisms so your tools can receive database connections, API clients, and other resources without managing their lifecycle. You can do that via:
InjectedToolArg
Runtime Context
ToolRuntime
What about skill scripts?
Skills can contain helper scripts (in a scripts/ subdirectory), but these should be deterministic, stateless utilities - think data transformation, file processing, or validation. From the skill-creator guidance:
“Deterministic reliability needed? Include script. Written repeatedly? Include script.”
Examples: PDF rotation, data formatting, template rendering. Not database connections or transaction management. Skill scripts are read and executed by the agent as needed, but they’re not the right abstraction for stateful operations.