We've all been there. You're reviewing a pull request from a junior developer, and for what feels like the tenth time this month, you're typing out the same comment:
"Hey, we don't use console.log in production code—please use our structured logger."
The dev apologizes, updates the code, and you approve the PR. Two weeks later, a different developer makes the exact same mistake. Rinse and repeat.
Sound familiar?
The Real Problem: The Documentation-Implementation Gap
Here's the thing: your team's architectural decisions live in documents that nobody reads, while the actual work happens in code.
You probably have an Architecture Decision Record (ADR) somewhere that clearly states: "We use Winston for structured logging, not console.log." It's documented. It's in Confluence. It might even be in your repository's /docs folder.
But let's be honest—when was the last time a developer actively searched through ADRs before writing code?
The problem isn't your team. The problem is expecting humans to remember and enforce dozens of architectural constraints manually. That's not scalable, and it leads to:
- Review fatigue: Senior devs waste time repeating the same feedback
- Inconsistent codebases: Some violations slip through when reviewers are tired
- Slower onboarding: New team members learn by making mistakes instead of prevention
- Context switching: Developers have to context-switch between code and documentation
What if there was a better way?
The Solution: Context-as-Code
Instead of keeping architectural decisions in separate documentation, what if we could encode them directly into our development workflow?
This is the concept of "Context-as-Code"—taking your team's architectural decisions and automating their enforcement at the exact moment they matter: during pull requests.
Think of it like this: instead of a senior developer manually checking every PR for violations, you create automated rules that check for you. The PR author gets immediate feedback, learns the constraint, and your reviewers can focus on actual architecture and logic instead of style guide enforcement.
Enter Decision Guardian
Decision Guardian is a GitHub Action that bridges this gap. It automatically surfaces architectural decisions and critical context when Pull Requests modify protected files. Instead of relying on tribal knowledge, Decision Guardian proactively alerts teams when changes touch sensitive code.
Here's what makes it powerful:
- Automated context surfacing: Automatically posts PR comments when protected files change
- Markdown-based decisions: Write decisions in simple markdown format
- Flexible file matching: Supports glob patterns and advanced rule evaluation
- Non-blocking: Configurable to either block merges or just warn
- Zero external calls: Runs entirely within your GitHub Actions runner—no data leaves GitHub
Let's dive into what this looks like in practice.
The Cool Stuff: Deep Dive into Features
Simple File-Based Decisions
The core concept is beautifully simple: you write architectural decisions in markdown and link them to file patterns. When someone opens a PR that touches those files, they automatically see the context.
Here's a basic example for protecting your database configuration:
<!-- DECISION-DB-001 -->
## Decision: Connection Pool Size
**Status**: Active
**Date**: 2024-01-15
**Severity**: Critical
**Files**:
- `src/db/pool.ts`
- `config/database.yml`
### Context
Pool size fixed at 20 connections to prevent exhaustion.
Tested with production load (5K req/s). Higher values caused
connection leaks under sustained traffic.
**Do not modify without load testing.**
---
That's it! When someone modifies src/db/pool.ts or config/database.yml, this decision automatically appears as a comment on their PR.
Advanced Rules with Regex
For more sophisticated scenarios, you can embed JSON-based rules directly in your markdown to detect patterns in code:
<!-- DECISION-SEC-001 -->
## Decision: No Hardcoded Credentials
**Status**: Active
**Date**: 2024-02-01
**Severity**: Critical
**Rules**:
\`\`\`json
{
"type": "file",
"pattern": "src/**/*.{ts,js}",
"exclude": "**/*.test.{ts,js}",
"content_rules": [
{
"mode": "regex",
"pattern": "(password|api[_-]?key|secret)\\s*[=:]\\s*['\"][^'\"]+['\"]",
"flags": "i"
}
]
}
\`\`\`
### Context
Detects hardcoded credentials. Use environment variables
or AWS Secrets Manager instead.
---
This rule will trigger when someone adds code like const password = "secret123" in a JavaScript/TypeScript file.
JSONPath for Configuration Files
You can also use JSONPath to validate specific values in JSON files:
<!-- DECISION-API-002 -->
## Decision: API Rate Limit Configuration
**Status**: Active
**Date**: 2024-03-10
**Severity**: Warning
**Rules**:
\`\`\`json
{
"type": "file",
"pattern": "config/api.json",
"content_rules": [
{
"mode": "json_path",
"path": "$.rateLimit.maxRequests",
"expected": 100
}
]
}
\`\`\`
### Context
Rate limit must stay at 100 requests/minute. Changes can:
- Block legitimate users (too strict)
- Allow abuse (too loose)
Before modifying, test with production traffic patterns.
---
Setting This Up (It's Easier Than You Think)
The beauty of Decision Guardian is its simplicity. No complex YAML configuration files—just markdown documents.
Step 1: Create Your Decisions File
Create .decispher/decisions.md in your repository:
<!-- DECISION-DB-001 -->
## Decision: Database Choice for Billing
**Status**: Active
**Date**: 2024-03-15
**Severity**: Critical
**Files**:
- `src/db/pool.ts`
- `config/database.{yml,yaml}`
### Context
We chose Postgres over MongoDB because billing requires ACID compliance.
MongoDB doesn't guarantee consistency for financial transactions.
**Alternatives rejected:**
- MongoDB: No ACID guarantees
- Redis: Added unnecessary complexity
**Related:**
- [Slack thread](https://your-workspace.slack.com/archives/...)
- [Architecture review](https://your-docs.com/...)
---
Step 2: Add the GitHub Action
Create .github/workflows/decision-guardian.yml:
name: Decision Guardian
on:
pull_request:
permissions:
pull-requests: write
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DecispherHQ/decision-guardian@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
decision_file: '.decispher/decisions.md'
fail_on_critical: true
Step 3: Test It Out
Create a test PR that modifies src/db/pool.ts and watch Decision Guardian automatically comment with the full context from DECISION-DB-001.
That's really it. No complex configuration files, no YAML sprawl—just markdown documents with your decisions.
What Makes This Different
You might be thinking: "Isn't this just like CODEOWNERS or linting?"
Not quite. Here's the key difference:
- CODEOWNERS assigns reviewers but doesn't explain why review matters
- Linting catches syntax errors but not architectural violations
- Decision Guardian provides context at the exact moment it's needed
When someone modifies your database connection pool, they don't just get an error—they get the full story: what the decision was, why it was made, what was tested, and who to talk to if they really need to change it.
Real-World Scenarios
Here are some practical examples of decisions teams protect with Decision Guardian:
Security patterns:
- No hardcoded credentials
- Required authentication middleware
- Specific encryption algorithms
Performance constraints:
- Database connection pool limits
- API rate limiting configurations
- Cache invalidation strategies
Architecture boundaries:
- Microservice communication patterns
- Dependency injection requirements
- Database access patterns
Business logic:
- Payment processing flows
- Data retention policies
- Feature flag configurations
Real-World Impact
After implementing Decision Guardian, teams typically see:
- Faster reviews: Senior developers spend less time on repetitive feedback
- Better onboarding: New developers learn architectural constraints immediately
- Consistent codebases: Violations get caught automatically, not sporadically
- Living documentation: ADRs become actionable, not just informational
- Knowledge preservation: Critical context survives even when team members leave
The real win isn't just catching violations—it's educating developers about why those violations matter. Each PR comment becomes a teaching moment.
Getting Started
The easiest way to start is to identify the top 3-5 architectural decisions you find yourself repeating in code reviews. Document them in markdown format, link them to the relevant files, and let Decision Guardian handle the rest.
Start small:
- Pick one decision that causes the most friction
- Document it in
.decispher/decisions.md - Add the GitHub Action
- Observe what happens over the next week
You can always expand from there.
Conclusion: Bridge the Gap
Decision Guardian represents a shift in how we think about documentation. Instead of static documents that live separately from our code, we can embed our architectural knowledge directly into the development workflow—right where developers need it.
This doesn't replace code review—it enhances it. Your senior developers can focus on architectural discussions, design patterns, and business logic instead of catching the same violations over and over.
If you're tired of repeating yourself in PR comments, give Decision Guardian a try. It's open source, free to use, and might just save your team hundreds of hours.
Resources
- Website: https://decision-guardian.decispher.com/
- Documentation: https://decision-guardian.decispher.com/docs
- GitHub Repository: https://github.com/DecispherHQ/decision-guardian
- GitHub Marketplace: Decision Guardian Action
Have you tried automating architectural decisions in your workflow? What challenges have you faced with keeping documentation and code in sync? Let me know in the comments!
Top comments (0)