How Agents Navigate¶
This document describes the implicit loop through which agents operate when embedded in a well-designed harness. This is not a hard specification—different teams will implement variations—but the pattern is consistent across harness implementations that follow the open standards. Because the loop is built on open standards (AGENTS.md, INVARIANTS.md, .agents/skills/), it is agent-agnostic: the same navigation pattern applies whether the agent is Claude, GitHub Copilot, Cursor, or any other tool implementing the specs.
- The Five-Step Agent Loop
- Looping on Failure
- The Shift in Workflow
- Practical Example: Code Review Task
The Five-Step Agent Loop¶
flowchart TD
S1["1. Discover Constraints<br/>AGENTS.md · INVARIANTS.md · SKILL.md"]
--> S2["2. Build Contextual Model<br/>architecture · decisions · task context"]
--> S3["3. Act Only via Allowed Surfaces<br/>tool calls · file edits · commands"]
--> S4["4. Self-Validate<br/>tests · linters · constraint checks"]
--> S5["5. Output & Report<br/>diff · rationale · constraint citations"]
Failures at any step trigger the decision tree in Looping on Failure below.
Step 1: Discover Constraints¶
What happens: Agent enters the repository and reads foundational documents.
Documents read:
- AGENTS.md (root) — Auto-loaded via tool-specific shim or native support; establishes repository-wide roles, footguns, and the link to INVARIANTS.md
- INVARIANTS.md — What absolutely cannot be changed?
- Relevant SKILL.md files — What can I do, and how do I do it for this task?
- Nearest module AGENTS.md (if present) — What local constraints apply here? (found via folder walk and navigation links)
Key principle: In a well-designed harness, the agent's behavior is driven by discovered rules rather than invented ones.
Example:
Agent starts CodeReview task
→ AGENTS.md auto-loaded: "CodeReviewer role: validate changes against architecture"
→ INVARIANTS.md linked from AGENTS.md: "All API changes require OpenAPI spec updates"
→ Reads relevant SKILL.md: "Can propose changes, but merge requires review"
→ Continues to Step 2 with constraints internalized
Step 2: Build Contextual Model¶
What happens: Agent assembles the specific context needed for this task.
Context sources:
- Module-level AGENTS.md (if applicable) — Local constraints for this area of code; keep these files concise to avoid context pollution
- Architecture docs (docs/ARCHITECTURE.md) — How does this part of the system fit?
- Decision records (docs/DECISIONS.md, if linked from AGENTS.md) — Why were previous choices made this way?
- Task-specific context — The code being reviewed, the test results, the change being proposed
Decision point: Context pruning kicks in if the window fills. The engineering-time practices that manage this are harness file size budgets and progressive discovery (see chapter 09); specific in-session pruning logic is a runtime configuration concern outside this guide's scope.
Key principle: The agent builds a model constrained by documented rules, not free-form prompting.
Example:
Task: Review a new API endpoint proposal
→ Load docs/ARCHITECTURE.md (how APIs are structured here)
→ Load existing openapi.yaml (API contract standard)
→ Load the proposed code and test cases
→ Load previous API review decisions from DECISIONS.md
→ Prune to fit token limit (keep all invariants, remove low-value examples)
→ Ready to analyze with full context about how things work here
Step 3: Act Only Via Allowed Surfaces¶
What happens: Agent takes action, but only through permitted channels.
Allowed surfaces:
- Code modifications (within boundaries specified in AGENTS.md)
- Commands via make targets (no direct shell commands)
- Tool calls (pre-approved tools with pre-defined inputs/outputs)
Validation: Each action is checked against tool & permission boundaries. - Is this tool in the allowed list? - Are the inputs valid and safe? - Does this operation require human approval? (If yes, agent stops and asks)
Key principle: A well-designed harness makes it significantly harder for an agent to invent new actions or bypass guardrails. The Makefile comment is soft enforcement — see Layer 4 for the distinction between soft and hard enforcement.
Example:
Agent proposes: "I'll modify the schema and run make test"
→ Check: Is "modify schema" allowed? YES (in src/ directory)
→ Check: Is "make test" allowed? YES (it's in Makefile)
→ Execute: Modify file, run make test
→ Next: If test passes, proceed to Step 4; if fails, diagnose and retry
Agent proposes: "I'll update the CI/CD config"
→ Check: Is this allowed? NO (INVARIANTS.md forbids it without approval)
→ Action: Agent stops, explains why it's stopping, escalates to human
Step 4: Self-Validate¶
What happens: Agent runs automated checks on its output before declaring success.
Checks performed:
- Tests: make test passes
- Linters/formatters: make lint and make format pass
- Type checks: make typecheck passes
- Schema validation: Generated API responses match openapi.yaml
- Policy checks: Custom sensors (security, performance, compliance)
Convenience target: Most repositories provide make check to run all critical sensors at once.
What if checks fail? - If failure is clear (e.g., test failure), agent diagnoses and retries - If failure is ambiguous, agent explains the failure to a human and stops - If check indicates a constraint violation, agent backtracks and tries a different approach
Key principle: Agent validation happens before human review, reducing review burden.
Example:
Agent runs: make check
→ Tests: PASS
→ Lint: 3 style issues found
→ Agent auto-fixes with: make format
→ Lint again: PASS
→ Type check: PASS
→ Result: All checks pass
→ Proceed to Step 5
Alternative:
Agent runs: make check
→ Tests: FAIL (test_api_contract failed)
→ Agent reads test output: "Expected 'type' field in response"
→ Agent reviews code: Field was missing from schema
→ Agent adds field and re-runs make check
→ Tests: PASS
→ Proceed to Step 5
Step 5: Produce Legible Output¶
What happens: Agent generates output that is easy for humans to review and understand.
Output characteristics:
Small diffs: Changes are focused and easy to review. - Don't make 3 unrelated changes in one PR; make 3 separate PRs - If possible, break large changes into reviewable chunks
Explicit reasoning: Commit messages and PR descriptions clearly explain why.
Example commit message:
Bad: "Fix API"
Good: "Add 'type' field to UserResponse schema per OpenAPI 3.0 spec"
Example PR description:
Bad: "Changes to payment logic"
Good: "Refactor payment retry logic:
- Changed retry backoff from linear to exponential
- Reason: Reduces server load during outages (per incident ADR-2024-005)
- Testing: Added 3 new test cases for edge cases
- Risk: Backwards compatible; existing payments unaffected"
Citation of constraints: If something was rejected or changed due to a constraint, say so explicitly.
"This change was modified to comply with INVARIANTS.md#no-direct-db-writes
(all DB changes must go through migrations). Updated to use new migration
framework instead."
Key principle: Output is auditable and maintainable, not just correct.
Example:
Agent output:
COMMIT: "Add OpenAPI spec validation to API integration tests"
- Added schema validation for POST /users endpoint
- Tests now enforce request/response contracts match openapi.yaml
- Reason: Prevents drift between spec and implementation (INVARIANTS.md)
CHANGES: 1 file changed, 15 lines added
- tests/test_api_contracts.py (new validation)
VALIDATION: make check ✓
- Tests pass
- Linters pass
- Type checks pass
HUMAN REVIEW: Ready for merge (no approvals required for test additions)
Looping on Failure¶
If any step fails, the agent has a decision tree:
flowchart TD
S1[Step 1: Discover Constraints] -->|Missing / unclear docs| E1([Escalate to human])
S1 -->|OK| S2[Step 2: Build Context]
S2 -->|Conflicting information| E2([Escalate to human])
S2 -->|Context window exceeded| P2[Apply pruning rules]
P2 -->|Retry| S2
S2 -->|OK| S3[Step 3: Act]
S3 -->|Action not allowed| H3([Explain and stop])
S3 -->|Unexpected side effect| R3[Rollback and diagnose]
R3 -->|Retry| S3
S3 -->|OK| S4[Step 4: Self-Validate]
S4 -->|Test or type error| F4[Diagnose and fix]
F4 -->|Retry| S4
S4 -->|Constraint violation| B4[Backtrack]
B4 -->|Try different approach| S3
S4 -->|Ambiguous failure| H4([Explain and stop])
S4 -->|OK| S5[Step 5: Output]
S5 -->|Explanation unclear| O5[Revise output]
O5 -->|Retry| S5
S5 -->|OK| Done([Output is legible and auditable])
Key principle: At each step, failure is a signal, not a termination. The agent has options: 1. Auto-fix and retry (if the solution is clear) 2. Diagnose and explain (if requiring human intervention) 3. Escalate (if beyond agent authority)
The Shift in Workflow¶
Old workflow (Ad-hoc prompting):¶
flowchart TD
A1(["Human: generate endpoint"]) --> B1[Agent generates code]
B1 --> C1[Human reviews manually]
C1 --> D1[Human tests manually]
D1 --> E1{Issues?}
E1 -->|Yes - repeat| B1
E1 -->|Acceptable| Done1([Done])
Problem: Every error requires human intervention and context-switching.
New workflow (with a repository harness):¶
flowchart TD
A2(["Agent: generate endpoint"]) --> B2["Discover constraints<br/>(AGENTS.md, SKILL.md, INVARIANTS.md)"]
B2 --> C2["Build context<br/>(docs, existing code)"]
C2 --> D2[Generate code within boundaries]
D2 --> E2["Self-validate<br/>(tests, linters, contracts)"]
E2 --> F2["Produce legible diff<br/>with clear reasoning"]
F2 --> G2([Human reviews and approves])
Advantage: Human review becomes lightweight; validation is automated; context is explicit.
Practical Example: Code Review Task¶
The CodeReview example threaded through Steps 1–5 above is this walkthrough — discover constraints, build context, act only via allowed surfaces, self-validate, produce legible output. For full, prompt-driven implementation examples, see Build Your Harness (Phase 5 validation prompts).
This workflow keeps roles clear: agents handle context and validation; humans handle judgment and approval. Chapter 06 shows what this pattern looks like applied across a full reference repository layout.
← Previous: Harness Components · Next: Reference Layout