Context Merging Reference
This document describes the exact rules for how context sources are merged and deduplicated.
Context Categories
Context is divided into two categories with separate handling:
Category 1: Project Context
- Sources:
[[project.context]]inproject.toml - Prompt Location: Appended to
project.config.xml/mdsection - Applies To: All workflow commands
Category 2: Target-Operation Context
- Sources:
[[workflows.context]]incommands.toml(target level)[[workflows.operations.context]]incommands.toml(operation level)--context-fileCLI flags--context-dirCLI flags
- Prompt Location: Rendered in
context.config.xml/mdsection - Applies To: Specific target and/or operation
Merging Rules
Within a Category
Sources within the same category are merged (union):
Target context: [A, B]
Operation context: [C, D]
CLI files: [E]
CLI dirs: [F/]
───────────────────────
Result: [A, B, C, D, E, F/*]
Deduplication
Files are deduplicated within each category by canonical path:
- All paths are resolved to absolute, canonical form
- Symlinks are followed
- Duplicate canonical paths are removed (first occurrence kept)
Example:
Input: ["./docs/readme.md", "docs/readme.md", "../project/docs/readme.md"]
After canonicalization: ["/project/docs/readme.md", "/project/docs/readme.md", "/project/docs/readme.md"]
After deduplication: ["/project/docs/readme.md"]
Across Categories
There is NO deduplication between categories:
Project context: [docs/architecture.md]
Target-operation context: [docs/architecture.md]
───────────────────────
Result: File appears in BOTH project.config AND context.config sections
This is intentional:
- Project context provides foundational understanding
- Target-operation context provides task-specific reference
- Same document may serve both purposes
Prompt Structure
Final prompt structure with both context categories:
[Role Prompt]
---
[Project Config + Project Context]
---
[Service Config (if monorepo)]
---
[Task Prompt]
---
[Target-Operation Context]
---
[User Input (if modifier)]
---
[Commit Config (if applicable)]
Directory Expansion
Directory sources are expanded inline:
[[workflows.context]]
type = "directory"
path = "docs/patterns/"
Becomes:
docs/patterns/singleton.md
docs/patterns/factory.md
docs/patterns/observer.md
Each file is treated as an individual source with:
original_path:docs/patterns/singleton.mddescription: Inherited from directory source + “(from directory)”
Precedence
Context sources are accumulated, not overridden. There is no “precedence” in the traditional sense - all sources are included.
However, the order of sources matters for AI interpretation:
- Project context appears early (in project.config section)
- Target context appears in context.config section
- Operation context follows target context
- CLI files follow operation context
- CLI directories appear last
Files listed earlier may have slightly more influence on AI behavior, but all context is considered.
Limits
File Count Limits
- Per directory source: 100 files maximum
- Total: No global limit (but context window limits apply)
File Size Limits
- Per file: 1MB maximum
- Binary files: Automatically skipped
Path Security
- Absolute paths: Must resolve within repository boundary
- Relative paths: Resolved from repository root
- Symlinks: Followed, must resolve within repository
Error Handling
Invalid Paths
Invalid paths cause immediate failure during config load:
Error: Context file not found: docs/missing.md
Source: project.toml [[project.context]][0]
Directory Traversal Limits
When limits are reached, processing continues with warnings:
Warning: Maximum file limit (100) reached for directory docs/
Skipped remaining files
Binary/Large File Skipping
Binary and oversized files are silently skipped:
Skipped: docs/diagram.png (binary)
Skipped: docs/dump.sql (exceeds 1MB limit)
These appear in transaction logs but not as errors.
Debugging
View Active Context
# Print prompt without execution
nia issue draft --print-prompt
# Check transaction logs
cat .nia/logs/transactions/latest.json | jq '.context_sources'
Context Source Tracking
Each context file is tagged with its origin:
| Origin | Description |
|---|---|
ProjectConfig | From project.toml [[project.context]] |
TargetConfig | From commands.toml [[workflows.context]] |
OperationConfig | From commands.toml [[workflows.operations.context]] |
CliFile | From --context-file flag |
CliDirectory | From --context-dir flag |
Transaction logs include:
- Original path
- Canonical path
- Origin
- Size (bytes)
- Description
Examples
Example 1: Simple Merge
Configuration:
# project.toml
[[project.context]]
type = "file"
path = "docs/arch.md"
# commands.toml
[[workflows.context]]
type = "file"
path = "docs/patterns.md"
Command:
nia code create --context-file docs/example.md
Result:
- Project context:
docs/arch.md - Target-operation context:
docs/patterns.md,docs/example.md
Example 2: Deduplication
Configuration:
# commands.toml
[[workflows.context]]
type = "file"
path = "docs/api.md"
[[workflows.operations.context]]
type = "file"
path = "docs/api.md" # Same file!
Result:
- Only one copy of
docs/api.mdin context.config section - First occurrence preserved
Example 3: Cross-Category Duplication
Configuration:
# project.toml
[[project.context]]
type = "file"
path = "docs/arch.md"
# commands.toml
[[workflows.context]]
type = "file"
path = "docs/arch.md" # Same file!
Result:
docs/arch.mdappears in both project.config and context.config- This is intentional - different purposes
Example 4: Directory Expansion
Directory structure:
docs/patterns/
├── singleton.md
├── factory.md
└── observer.md
Configuration:
[[workflows.context]]
type = "directory"
path = "docs/patterns/"
Result: Three separate files in context.config:
docs/patterns/singleton.mddocs/patterns/factory.mddocs/patterns/observer.md
Implementation Notes
Canonical Path Resolution
Canonical paths are computed using:
Path::canonicalize()to resolve symlinks and relative components- Result must be within repository boundaries
- Paths outside repository are rejected
Hidden Directory Exclusion
The following directories are automatically excluded:
.git.nianode_modules.venv__pycache__.mypy_cachetarget(Rust)distbuild
Binary File Detection
Files are considered binary if:
- Magic number indicates binary format (PNG, JPEG, PDF, etc.)
- Extension indicates binary (.exe, .dll, .so, .dylib, etc.)
- First 8KB contains null bytes
See Also
- Context Sources - Configuration syntax
- Context Usage Patterns - Common patterns
- Command Reference - CLI flags