policy.md and Agent Status: Boundaries, States, and Skills
policy.md and Agent Status: Boundaries, States, and Skills
Yesterday we talked about this: every agent needs a place in your organizational chart, with a clear owner (responsible_id). But naming an agent is not enough. You also need to define what it can do, what it cannot do, which tools it can use, and what limits it must stay within.
Because when an agent receives a task, who does it ask? The same way a human employee does. If a salesperson is new and doesn’t know whether they can offer a customer a guarantee, what are the rules? Where are those rules written?
They should be in “operating policy” files.
policy.md: An Agent’s Operating Rules
An agent needs the following information to operate safely:
- What is it responsible for? Which jobs does it do, which does it avoid?
- What tools can it access? Database, API, file system, network, external services. Which ones?
- What happens if there is an error or risk? Can it ask for approval? Can it delay human intervention?
- Who does it report its results to? Directly to its owner, or to a central log?
These rules live in policy.md.
# Agent: Data Cleaner Agent (data_cleaner_001)
## Responsibility
- Cleans incoming CSV files: removes missing rows, duplicates, malformed records
- Rules: RFC 4180 CSV standard, UTF-8 encoding, reject files over 10 MB
## Access
- Tool: S3 bucket "raw_data" (read), "cleaned_data" (write)
- Tool: Slack API (report success/failure)
- Limit: Do not reprocess the same file more than 3 times
- Blocked: Access to human records, external API calls
## Error Policy
- Processing fails: Log to Slack #data-ops
- More than 5 errors: Request human intervention
- Sensitive data detected (SSN, IP): Stop immediately, alert responsible_id
## Reporting
- Daily summary: Slack #data-ops, 08:00 UTC
- Detailed logs: S3 "logs" bucket as .json
See? These rules make it crystal clear what the agent does. And they are versioned in Git. If something changes, a human reviews it in a PR.
Agent States: Draft, Active, Inactive
An agent is not always active. It has a lifecycle.
Draft
- Newly written, tested in isolation, but not yet ready for production
- Policy may not be complete, skills may not be fully validated
- Runs only in development and test environments
- Lives in a Git branch, not main
Active
- Running in production, doing real work
- Policy is complete, skill tests pass, owner accepts responsibility
- In Git main branch, marked
status: activeinconfig/agents.yaml
Inactive
- No longer running, but we keep it
- Even though it is not used, its policy and history stay
- Maybe it will be needed again; maybe an old agent does something that is no longer useful
- Stays in Git history, marked
status: inactive
agents:
data_cleaner_001:
name: "Data Cleaner Agent"
owner: "person_Alice_DataOps"
status: active # Currently running
created: 2026-08-15
policy: "policy/data_cleaner_001.md"
report_generator_v1:
name: "Report Generator (Old)"
owner: "person_Bob_Analytics"
status: inactive # Previous version, replaced by v2
created: 2025-06-01
retired: 2026-08-01
policy: "policy/report_generator_v1.md"
Skill Types: An Agent’s Toolkit
What an agent can do is defined by its “skills” — the tools available to it. There are four types:
builtin: Defined in the agent’s code
- Example: text processing, simple math, data transformation
- Fast, no dependencies, safe because code-reviewable
mcp (Model Context Protocol): Connection to an external system
- Example: Slack API, GitHub API, Jira
- Standard interface, managed connection, built-in auth
http: Free-form HTTP call
- Example: call a REST API of a third-party service, your own API endpoint
- Flexible, but risky; URL validation and rate limits are mandatory
function: External Python/Node.js function
- Example: database query, call an ML model
- Powerful, but risky; running external code is a security concern
agents:
data_cleaner_001:
skills:
- type: builtin
name: "csv_validate" # RFC 4180 validation
- type: mcp
name: "slack_notify" # Send Slack message
- type: http
name: "call_external_clean" # Third-party API
config:
url: "https://api.cleaning-service.com/clean"
timeout_sec: 30
- type: function
name: "db_update" # Write to database
config:
runtime: python
path: "functions/db_update.py"
What is this design the opposite of? Control and visibility. When an agent is designed, its policy is written, its skills are coded, all of it goes into Git. A human reads it, a PR review runs, approval is given. Then it goes active.
Shadow AI is the opposite. Everyone opens their own ChatGPT, nobody knows what anybody is doing. But in an organization with rules, an agent and its policy are in Git, visible to the world.
Tomorrow we will talk about: how does one agent hand off work to another?