Abstract: Configuration files traditionally serve as "settings" or "tuning knobs" for software tools. This document argues for a more fundamental role: configuration as executable documentation of project semantics. We examine how Reveal's .reveal.yaml specification demonstrates this pattern, connecting to SIL's principles of explicit meaning, progressive disclosure, and tool behavior contracts.
Correction (2026-08-04): Sections 2, 3, and 4 originally presented a
semantic://adapter/custom_patternsconfig and anast.entry_pointsconfig as part of Reveal's shipped.reveal.yamlspecification. Neither was ever implemented, at the document's 2025-12-22 publication or since (checked against v0.113.0).semantic://was explicitly evaluated and rejected — reveal's ROADMAP.md lists it under "Explicitly Not Planned" ("requires ML infrastructure; over-engineered").entry_pointswas never built, though the underlying gap it addresses is real and now tracked as BACK-952. What is real and unchanged:architecture.layers(withpaths/allow_imports/deny_imports, not thepath/can_import/cannot_importfield names used below) and~/.reveal/rules/custom-rule plugins (with theBaseRuleAPI, not aRuleclass). Examples below are corrected inline; §7's "Future Research" framing already correctly marked these as speculative and is left as-is.
1. The Problem with Traditional Configuration
1.1 Configuration Drift
Teams often declare architectural intentions ("we follow clean architecture") without enforcement mechanisms. Over time:
- Intent lives in documentation (e.g., "routes shouldn't call repositories directly")
- Reality lives in code (but a developer adds
from repositories import UserRepoto save time) - No automated check catches the violation
- Drift accumulates until architecture is unrecognizable
Result: Architecture documentation becomes archaeological artifact rather than living contract.
1.2 Binary Configuration Choices
Most tools force binary decisions:
Option A: Zero Configuration ("Convention over configuration")
- ✅ Simple to start
- ❌ No project-specific customization
- ❌ Generic rules don't match team reality
- Example: ESLint's default rules may not match your architecture
Option B: Configuration Everything ("Explicit over implicit")
- ✅ Full control
- ❌ Configuration complexity rivals codebase
- ❌ Barrier to entry (new devs overwhelmed)
- Example: Webpack configs that need configs
The gap: No middle path that scales complexity with project needs.
1.3 Configuration as Settings (Not Semantics)
Traditional configuration treats settings as opaque values:
# Traditional approach
max_line_length: 120
complexity_threshold: 10
These are tuning parameters, not semantic declarations. They answer "how much?" but not "what does this mean for our system?"
2. Configuration as Semantic Contract
2.1 Core Insight
Configuration should declare project semantics, not just tune behavior.
Instead of:
ignore_patterns: ["**/tests/**"] # What does this mean?
We declare (a proposed config shape — not implemented, see BACK-952 — shown here to illustrate the concept; reveal's actual --uncalled already recognizes pytest test functions via a hardcoded built-in list, just not a configurable one):
ast:
entry_points:
- pattern: "def test_"
description: "Pytest test functions"
languages: [python]
Difference:
- Traditional: "Ignore this path" (mechanism)
- Semantic: "These functions are entry points invoked by pytest" (meaning)
2.2 Executable Documentation
Configuration becomes executable documentation when:
- It declares intent (not just parameters)
- Tools enforce it (violations detected automatically)
- It's version-controlled (evolves with codebase)
- It's team-shared (everyone sees same rules)
Example from Reveal (real, working config — field names corrected: paths/deny_imports, not path/cannot_import):
architecture:
layers:
- name: routes
paths: [app/routes/**]
description: "HTTP route handlers"
deny_imports:
- repositories # Routes must go through services
- name: services
paths: [app/services/**]
description: "Business logic layer"
deny_imports:
- routes
This configuration IS the architecture. The tool enforces what the team means by "layered architecture."
2.3 Connection to SIL Principle #2: Meaning Must Be Explicit
From architectural-principles.md:
Principle #2: Meaning Must Be Explicit
Semantic infrastructure makes meaning first-class. All meaningful objects are typed, inspectable semantic structures—not implicit conventions or documentation promises.
How configuration embodies this:
- Layer boundaries are explicit typed structures (not implicit conventions)
- Entry points are declared patterns (not "developers should know")
- Custom semantics are named patterns (not "search the code for Stripe calls")
Traditional configuration: "Here are some settings"
Semantic configuration: "Here is what these structures mean in our system"
3. Reveal's YAML Specification: Case Study
3.1 Progressive Configuration Pattern
Reveal demonstrates progressive configuration matching the three-level progressive disclosure pattern:
Level 1: Zero Config (Intelligent Defaults)
reveal app.py # Works immediately
reveal app.py --check # Quality checks with sensible rules
Level 2: Project Overrides (.reveal.yaml)
# .reveal.yaml - Project-specific semantics
architecture:
layers:
- name: routes
paths: [app/routes/**]
deny_imports: [repositories]
rules:
C901:
threshold: 15 # cyclomatic complexity
Level 3: Custom Extensions (~/.reveal/rules/)
# ~/.reveal/rules/stripe_usage.py
# Team-specific custom rule for tracking payment code
Key insight: Complexity cost is opt-in. Teams pay for what they need.
3.2 URI Schemes = Composable Queries (No Named Custom Patterns)
Reveal's URI adapter system (24 adapters — ast://, calls://, imports://, etc.) enables queryable domain knowledge without configuration:
reveal 'ast://app?complexity>10'
reveal 'calls://app/?target=charge_card'
reveal app/ --grep 'stripe\.'
Correction: the semantic: custom_patterns config and semantic:// adapter shown in the original version of this section (for saving a named pattern like uses_stripe_api as a queryable identifier) were never built. This was evaluated and explicitly rejected: reveal's ROADMAP.md lists "semantic:// embedding search" under "Explicitly Not Planned" — "requires ML infrastructure; over-engineered." Domain-specific queries today are ad hoc --grep/ast:// invocations, not named, saved, first-class semantics — "what code touches our payment provider?" still requires knowing (or writing down elsewhere) the right grep pattern, not a config-declared vocabulary. The USIR connection below remains aspirational, not something Reveal's config implements.
3.3 Entry Points and Dead-Code Detection
Modern frameworks use implicit invocation (decorators, dependency injection, event handlers). Dead code detection fails because tools don't understand "framework magic."
What Reveal actually does today: calls://?uncalled recognizes a fixed, built-in set — property/classmethod/staticmethod, pytest fixtures/test_*, unittest lifecycle methods, C#/Java test attributes (BACK-446) — but nothing for web/CLI framework routes (Flask/FastAPI/FastHTML @app.route, Click @click.command, Django views). Those still false-flag as dead code.
Proposed, not implemented (would extend the built-in list to be project-configurable — filed as BACK-952):
ast:
entry_points:
- pattern: "@app\\.(route|get|post)"
description: "FastHTML route handlers"
languages: [python]
- pattern: "@click\\.command"
description: "Click CLI commands"
languages: [python]
Benefit (if built): Teaches tools about framework invocation patterns. What was "magic" becomes declared semantic contract.
Generalization: Any implicit invocation pattern can be declared:
- Event handlers (addEventListener, React hooks)
- Dependency injection (@Injectable, Spring beans)
- Plugin systems (Jupyter kernels, VSCode extensions)
3.4 Team-Shareable Architectural Rules
The free-form architecture.rules[].check: "<expression>" DSL shown below was never implemented — no arbitrary-expression rule engine exists in .reveal.yaml. What's real is per-built-in-rule threshold overrides (keyed by rule code, e.g. rules: {C901: {threshold: 15}}) plus the architecture.layers import-boundary mechanism from §2.2/§3.1. The example is left as illustrative of the idea, not a working config:
# NOT IMPLEMENTED — illustrative only
architecture:
rules:
- name: no-god-functions
check: function_lines <= 100
severity: error
message: "Functions should be under 100 lines for maintainability"
- name: models-import-restrictions
pattern: "app/models/**/*.py"
check: "only imports from [typing, pydantic, datetime, enum]"
severity: error
message: "Models should have no business logic dependencies"
Distinction from ESLint/Pylint:
- Global rules: Apply same rules everywhere
- Semantic rules: Different rules for different architectural layers
Example: Services can import repositories, but routes cannot. This is architecture-aware.
4. Theoretical Foundations
4.1 Configuration as Tool Behavior Contract (TBC)
From LAYER3_SUBLAYER_ARCHITECTURE.md, every tool should answer:
- How does it execute? (mode: sync/async/job/session)
- What channels does it use? (stdin, stdout, stderr, events)
- How do you track progress?
- What permissions does it need?
- How do I invoke and monitor you?
Configuration extends this:
The .reveal.yaml file documents how Reveal should behave for this project:
# Execution mode: How should unused imports be detected?
imports:
ignore_unused: [...] # Context-specific execution rules
# Permissions: What can different layers access?
architecture:
layers:
- name: routes
paths: [app/routes/**]
deny_imports: [repositories] # Permission boundaries
Key insight: Configuration is metadata about tool behavior in project context.
4.2 Invariants Over Layers
From architectural-principles.md:
Principle #4: Invariants Define Correctness
Correctness in semantic infrastructure comes from preserved invariants, not intuition or guidelines.
How configuration encodes invariants:
architecture:
layers:
- name: models
paths: [app/models/**]
allow_imports: [typing, pydantic, datetime, enum]
deny_imports: [services, routes, repositories]
This declares an invariant: "Models have no business logic dependencies"
Verification: Tool checks imports → violations break the build → invariant enforced
Traditional approach: Write this in documentation, hope developers remember, catch in code review (maybe).
Semantic approach: Declare the invariant, automate verification, make violation impossible to merge.
4.3 Multi-Agent Protocol Principles
From MULTI_AGENT_PROTOCOL_PRINCIPLES.md:
Principle 2: All communication must be typed
Input/output schemas prevent silent failures
How configuration would support this, if the semantic: config existed (it doesn't — see §3.2 correction):
# NOT IMPLEMENTED — rejected per ROADMAP.md, "Explicitly Not Planned"
semantic:
custom_patterns:
- name: uses_email
description: "Functions that send email"
languages: [python]
patterns: ["send.*email", "EmailMessage"]
Result (hypothetical): Agents could query "what functions send email?" with typed responses. Today, an agent gets the same answer via reveal app/ --grep 'send.*email|EmailMessage', just without a saved name for the pattern.
5. Broader Implications
5.1 Pattern Applies Beyond Code Analysis
The "configuration as semantic contract" pattern generalizes:
Documentation Structure:
# docs.yaml
structure:
- section: foundations
audience: [newcomers, researchers]
reading_time: 30min
dependencies: []
- section: systems
audience: [developers]
reading_time: 2hr
dependencies: [foundations]
API Contracts:
# api.yaml
endpoints:
- path: /api/users
rate_limit: 1000/hour
auth_required: true
data_sensitivity: PII
cannot_call: [/api/admin/**] # Security boundary
Deployment Rules:
# deployment.yaml
environments:
- name: production
branch: main
auto_deploy: false # Invariant: prod requires approval
required_checks: [tests, security_scan, architecture_validation]
Common pattern: Declare semantic constraints, enforce automatically, version-control the contract.
5.2 Configuration as Team Alignment Mechanism
Traditional alignment:
- Write architecture docs
- Explain in meetings
- Hope everyone remembers
- Catch drift in code reviews
Semantic configuration alignment:
- Declare architecture in .reveal.yaml
- Commit to version control
- Tool enforces on every commit
- Violations fail CI immediately
Result: Architecture cannot drift silently. The configuration is living documentation.
5.3 Enabling Progressive Complexity
The problem with "zero config" tools:
- Great for simple projects
- Break down as complexity scales
- Force users to eject entirely (React's eject pattern)
The problem with "configure everything" tools:
- Overwhelming for simple projects
- Barrier to entry too high
- Configuration becomes second codebase
Progressive configuration solves this:
- Start with intelligent defaults
- Add project overrides as needed
- Extend with custom rules when domain-specific
- Complexity scales with actual project needs
6. Connection to SIL Research Themes
6.1 Progressive Disclosure (Theme: Information Architecture)
Configuration follows three-level progressive disclosure:
Level 1: Tool works with zero config (intelligent defaults)
Level 2: Project declares overrides (.reveal.yaml)
Level 3: Team extends with custom semantics (~/.reveal/rules/)
See: PROGRESSIVE_DISCLOSURE_GUIDE.md
6.2 Agent-Help Standard (Theme: Agent Infrastructure)
Configuration becomes machine-readable tool contract:
reveal --agent-help # General usage
reveal architecture src/ # Architectural brief for a directory (entry points, risks, next commands)
The configuration documents project-specific semantics that agents can query.
6.3 Tool Behavior Contracts (Theme: Agent Infrastructure)
Configuration answers the TBC questions for project context:
- How does this tool behave for this project?
- What are the project-specific rules?
- What semantic patterns exist in this codebase?
See: LAYER3_SUBLAYER_ARCHITECTURE.md
6.4 Structure Before Heuristics (Theme: Architectural Principles)
Traditional linters: Heuristics for "code smells"
Semantic configuration: Explicit structural rules
# Not: "Complexity seems high" (heuristic)
# Instead: "Functions in services/ must be under 100 lines" (structure)
architecture:
rules:
- pattern: "app/services/**"
check: function_lines <= 100
See: architectural-principles.md
7. Future Research Directions
7.1 Configuration as Trust Assertion
Could configuration declare capability requirements?
# Hypothetical: Trust Assertion Protocol integration
trust:
capabilities:
- name: network_access
required_for: [semantic://app?makes_http_call]
justification: "External API calls for data enrichment"
Vision: Configuration declares what capabilities code needs, TAP verifies at runtime.
See: TRUST_ASSERTION_PROTOCOL.md
7.2 Multi-Agent Configuration Contracts
Could teams declare agent behavior contracts in configuration?
# Hypothetical: Agent Ether integration
agents:
code_reviewer:
can_read: [src/**, tests/**]
can_write: [tests/**]
cannot_write: [src/**] # Read-only for source
required_approval: [human] # Must get human approval
test_generator:
can_read: [src/**]
can_write: [tests/**]
auto_commit: true # Can commit directly
Vision: Configuration as multi-agent protocol contract (not just single-tool settings).
7.3 Cross-Project Semantic Standards
Could projects declare semantic compatibility?
# Hypothetical: USIR compatibility declaration
semantics:
compatible_with:
- usir: v1.0
- domain: code-understanding
exports:
- type: ArchitectureGraph
version: 1.0
schema: ./schemas/architecture.yaml
Vision: Projects declare semantic exports, other tools can depend on them.
8. Practical Guidelines
8.1 When to Use Semantic Configuration
Use semantic configuration when:
✅ Team alignment matters (architecture rules, conventions)
✅ Domain knowledge is valuable (custom patterns, project-specific semantics)
✅ Enforcement prevents drift (layer boundaries, invariants)
✅ Configuration is shared (version-controlled, team-wide)
Don't use semantic configuration for:
❌ Personal preferences (tabs vs spaces, editor settings)
❌ Purely aesthetic rules (no semantic meaning)
❌ Rules that can't be verified (vague guidelines)
8.2 Design Principles for Semantic Config
1. Declare meaning, not mechanism
# ❌ Mechanism-focused
ignore_paths: ["tests/"]
# ✅ Meaning-focused
ast:
entry_points:
- pattern: "def test_"
description: "Test functions invoked by pytest"
2. Make contracts explicit
# ❌ Implicit
max_imports: 10
# ✅ Explicit contract
architecture:
rules:
- name: minimize-coupling
check: import_count <= 10
message: "High import count suggests tight coupling"
3. Enable progressive adoption
- Level 1: Zero config (intelligent defaults)
- Level 2: Project overrides (common needs)
- Level 3: Custom extensions (domain-specific)
4. Version control and share
- Commit .reveal.yaml to repository
- Document why rules exist (not just what they check)
- Review config changes like code changes
9. Conclusion
Configuration as semantic contract transforms configuration from "settings file" to "executable documentation of project semantics."
Key insights:
- Configuration should declare meaning (not just tune parameters)
- Tools should enforce contracts (violations detected automatically)
- Progressive complexity (opt-in, scales with project needs)
- Team alignment (shared, version-controlled, living documentation)
Reveal's .reveal.yaml specification demonstrates:
- Progressive disclosure applied to configuration
- URI schemes + custom patterns = composable semantics
- Entry points as first-class framework integration concept
- Architecture-aware rules (not just global linting)
Connection to SIL:
- Embodies Principle #2 (Meaning Must Be Explicit)
- Extends Tool Behavior Contracts to project context
- Demonstrates Structure Before Heuristics
- Supports Agent-Help Standard with machine-readable contracts
Future potential:
- Integration with Trust Assertion Protocol (capability declarations)
- Multi-agent configuration contracts (Agent Ether)
- Cross-project semantic compatibility (USIR exports)
Bottom line: When configuration declares project semantics rather than just tuning behavior, it becomes infrastructure for maintaining architectural integrity—exactly the kind of semantic infrastructure SIL builds.
10. References
SIL Documents:
- Architectural Principles - Structure Before Heuristics, Meaning Must Be Explicit
- Progressive Disclosure Guide - Three-level pattern
- Agent-Help Standard - Machine-readable tool contracts
- Layer 3 Architecture - Tool Behavior Contracts
- Multi-Agent Protocol Principles - Typed communication
External References:
- Reveal .reveal.yaml (real, current example): /home/scottsen/src/projects/reveal/external-git/.reveal.yaml
- Reveal layer-config implementation: reveal/analyzers/imports/layers.py
- Reveal v0.113.0: current version at time of correction (2026-08-04); a REVEAL_YAML_CONFIG_SPEC.md referenced in an earlier draft of this document does not exist in the repo
Related Research:
- Configuration as code (infrastructure as code patterns)
- Design by contract (Bertrand Meyer)
- Type-driven development (dependent types, refinement types)
- Architecture decision records (ADRs)
Status: Published
Date: 2025-12-22 (corrected 2026-08-04)
Version: 1.1 — fabricated/unimplemented features (semantic://, ast.entry_points) corrected against actual v0.113.0 codebase; see note at top
Author: Semantic Infrastructure Lab
Maintainer: SIL Research Team
