The Basic Law of the Workspace: .agents.md Standards and Instruction Alignment
What (What this article is about)
.agents.md (or similar files like AGENTS.md / CLAUDE.md / Copilot instructions, etc.) is not a "README written for humans", but an "injectable rule set" written for the agent runtime. It tells the system what behaviors are allowed in this workspace, what is forbidden, and what must pass through quality gates (timeout, retry, idempotency, isolation, permissions, audit, observability).
This article explains the rule system as an engineerable module:
- The role and boundaries of rule files: what they solve and what they don't.
- Discovery and cascading of rules: directory-level stacking and override semantics.
- How rules enter the execution chain: injection points, assembly strategies, and audit evidence.
- Why "writing rules" must be coupled with quality gates and logs, otherwise accidents will still occur.
Problem (The engineering problem to be solved)
When an agent works in a repository, failures are often not "it doesn't know how to write code," but "it doesn't know your boundaries":
- Style Drift: Inconsistent indentation, naming conventions, and comment languages cause changes to spread, making review costs soar.
- Out-of-Bounds Read/Write: The agent modifies directories it shouldn't touch or writes temporary artifacts into the source tree, triggering rollback disasters.
- Architecture Decay: Business logic gets flattened into
components/orlib/, with deep cross-module imports violating dependency inversion. - Security Incidents: Writing secrets into the repository, packaging and exfiltrating sensitive files, or connecting to the network when it shouldn't.
- Un-Retrospectable: After an incident, you can only see "what it changed," but not "what rules it followed at the time and why it did it."
Therefore, the goal of a rule system is not to "make the agent smarter," but to shift risks from random to controllable: making errors predictable, blockable, rollback-able, and auditable.
Principle (Positioning of rule files: Persistent instructions, not runtime)
Many tools support placing a "rule file" in the repository and loading it when a session begins. JetBrains' documentation explicitly distinguishes between "instruction files carried with the repository (e.g., AGENTS.md / CLAUDE.md)" and the IDE's internal project rules. Your conclusion should be:
- Rule files are "persistent instruction carriers": versioned, reviewable, and rollback-able.
- The injection engine (runtime) is the "executor": it decides when to inject, how much to inject, how to prune, and how to record audit evidence.
- Quality gates and governance are the "hard constraints": timeouts, retries, idempotency, permissions, isolation, audits, and observability must be enforced at the execution layer.
No matter how beautifully rules are written, if the runtime doesn't execute them, they are merely literary works.
Usage (How to use it: Connecting the rule system to your control loop)
1) Rule files must be written as "executable constraints"
A good rule file is not an "initiative proposal," but a "judgable constraint." You should avoid:
- Vague words: "Try to," "preferably," "recommended."
- No quality gates: Saying "do not exceed permissions" without stating how privilege escalation is blocked.
- No scope: Failing to clarify which directories/files are off-limits and which tools are available.
Rules must be written in the following structure so the runtime can translate them into deterministic behaviors:
# Workspace Rules (for agent runtime injection)
## 1. Absolute Boundaries (CRITICAL)
- Write Forbidden: Any directory outside of content/ and src/
- Read Forbidden: Sensitive paths like .env, secrets/, ~/.ssh
- Network Forbidden: Unless explicitly permitted by the task (and record URL and retrieval date)
## 2. Engineering Gates (Must be executed)
- Every tool call must have: timeout, retry limit, idempotency key, audit fields
- Any write operation must go through patch submission: free writing directly in the workspace is forbidden
## 3. Architecture Constraints (Inspectable)
- features must be placed under src/features/<name>
- Cross-module imports can only import the other's index.ts (deep imports forbidden)
## 4. Conventions and Style (Mechanizable)
- Comments must be in Chinese
- One file, one class; class < 500 lines; method < 50 lines
Note the keywords here: timeout, retry, idempotency, permissions, isolation, audit, observability. The rule file must include these "accident defense lines," otherwise you can only patch things up after an accident happens.
2) Cascading Rules: Rules need to be composable
Large repositories are often multi-language and multi-module. You need to clarify the "effective scope of rules". A common approach is:
- Root directory rules: Global baselines (security, boundaries, audits, least privilege).
- Subdirectory rules: Local overrides (language stacks, test commands, module boundaries).
- Stacking semantics: The closer a rule is to the target file, the higher its priority, but it cannot break the absolute boundaries of the root directory.
Implement this as a deterministic algorithm, rather than "writing a few paragraphs hoping the model understands."
3) Rule Discoverer: Turning effective rules into audit evidence
The pseudocode below emphasizes two points:
- Rule discovery is deterministic (reproducible).
- Effective rules must be recorded (auditable, replayable).
import os
from dataclasses import dataclass
@dataclass(frozen=True)
class EffectiveRules:
# Rule content (final merged text)
text: str
# Source paths of rules (for auditing)
sources: list[str]
class RuleResolver:
"""
Rule Resolver:
Searches upwards from the target file for rule files to form an "effective rule set",
and records the source paths as audit evidence.
"""
def __init__(self, *, rule_filenames: list[str]):
self._rule_filenames = rule_filenames
def resolve(self, *, target_file_path: str, workspace_root: str) -> EffectiveRules:
cur = os.path.dirname(os.path.abspath(target_file_path))
root = os.path.abspath(workspace_root)
pieces: list[str] = []
sources: list[str] = []
while True:
for name in self._rule_filenames:
p = os.path.join(cur, name)
if os.path.exists(p):
with open(p, "r", encoding="utf-8") as f:
pieces.append(f.read())
sources.append(p)
if cur == root:
break
parent = os.path.dirname(cur)
if parent == cur:
break
cur = parent
# Convention: Deeper directories are more specific, so they are placed earlier when merged
pieces = list(reversed(pieces))
sources = list(reversed(sources))
return EffectiveRules(text="\n\n".join(pieces), sources=sources)
4) Injection Points: Rules should not be "fully stuffed in every round"
Rule injection must coordinate with the token budget:
- Stable prefixes: Core rules and tool schemas should remain as fixed as possible, aiding caching and stable behavior.
- On-demand pruning: Only inject rule parts relevant to the current task (e.g., only injecting "cross-module import constraints").
- Record assembly plans: Write which rule blocks were injected into the trace/span every round, otherwise retrospection is impossible.
Design (Design trade-offs: Why a "quality gate layer" is necessary)
Rule files mainly manage "intentions", while the quality gate layer manages "behaviors". These two must be separated:
- Rules tell you "what should be done."
- Quality gates ensure you "can only do it this way."
For example, a rule states "forbidden to write to sensitive directories," but what actually blocks the write should be:
- Path allowlists (permissions).
- Read-only mounts (isolation).
- Patch submission flow (audit).
- Timeout/retry limits (preventing infinite loops).
This is why the same set of rules behaves very differently under different runtimes: the key isn't the text, but the execution layer.
Pitfall (Common pitfalls and error prevention)
- Too many fragmented rules: A bunch of scattered rules leads to high injection costs and attention noise.
- Contradictory rules: Lacking "absolute boundaries" and "override priorities" leads to behavioral drift.
- Writing style but no gates: The most accident-prone issue isn't indentation, but privilege escalation and repeated side-effect submissions (idempotency).
- Not recording effective rules: Inability to answer "which set of rules was actually followed at that time" after an incident.
- Unversioned rules: Ad-hoc rule changes render online behavior untraceable and hard to rollback (audit).
Debug (How to debug the rule system)
Treat the rule system as a "testable module":
- Prepare a small test case for each directory to assert the source order and content merge order of effective rules.
- Record rule sources and hashes (content digests) in traces/spans to ensure online replayability.
- When out-of-bounds behavior occurs, check "were effective rules missing" first, then check "were quality gates executed."
Source (References)
- JetBrains instruction files: https://www.jetbrains.com/help/ai-assistant/configure-agent-behavior.html
- AGENTS.md / Rule carrier practice discussion: https://particula.tech/blog/agents-md-ai-coding-agent-configuration
- Rule carrier comparisons: https://www.chaitanyaprabuddha.com/blog/agents-md-vs-claude-md-vs-cursor-rules
- Engineered rule generation cases: https://github.com/naravid19/ai-project-rules-generator
Rule Checklist Template (Writing "executable constraints" completely)
Below is a checklist template closer to production. Its goal is not to be long, but to complete the "accident-related rules," avoiding only writing style constraints:
- Tool Constraints:
- Tool allowlist (which tools are permitted)
- Timeout and retry limit for each tool (timeout, retry)
- Whether an idempotency key is required (idempotency)
- Read/Write Boundaries:
- Allowlist of readable paths (permissions)
- Allowlist of writable paths (permissions)
- Forced read-only mounts and output directories (isolation)
- Network Boundaries:
- Allowlist of accessible domains/ports (permissions)
- Default deny policy (isolation)
- Audits and Observability:
- Every tool call must record: tool name, parameter summary, trace_id, timeout, retry count (audit, observability)
- Every write operation must produce: patch_id / commit_id / WAL record (audit)
- Failures and Degradation:
- Conditions triggering degradation (degradation)
- Conditions triggering rollback/compensation (rollback)
- Conditions triggering manual intervention (audit)
Once this checklist is written into the rule file, the injection engine has a chance to "land the rules onto the execution chain."
An Anti-Pattern (Explaining why writing only style is ineffective)
Below is a common but almost useless rule file (anti-pattern):
- "Please write clean code"
- "Please add comments"
- "Please follow the architecture"
Its problem is: no scope, no quality gates, no inspectable objects. When out-of-bounds writes, retried side-effects, or timeout freezes occur, these rules provide zero blocking capability.
Therefore, when writing rules, constantly ask yourself: Can this rule be mechanically executed by the runtime? If not, you must add quality gates and scope.