Semantic Merging
dkod understands code at the structural level, not the text level. This means two agents editing different functions in the same file is not a conflict — it's an automatic merge.
Why Git Merging Breaks Down
In Git, code is just text. When two developers (or two agents) edit the same file, Git compares line numbers. If the changes are anywhere near each other, you get a merge conflict — even if the changes are completely independent.
Example: False conflict in Git
Agent A modifies authenticate_user() in auth.rs. Agent B modifies reset_password() in the same file. Git sees two changes to auth.rs and reports a merge conflict. A human must manually resolve it, even though the changes don't interact at all.
This happens constantly with AI agents. When 5 agents work on the same codebase, they frequently touch the same files — not the same functions, but Git can't tell the difference.
The workaround today: worktrees. To avoid agents stepping on each other, teams use Git worktrees — each agent gets its own full copy of the repository checked out to a separate directory. 10 agents means 10 copies of the entire codebase on disk. A 2GB repo with 10 agents is 20GB of disk space, plus the time to set up each worktree, each on its own branch.
And it gets worse. You have to carefully manage those worktrees — create them, assign branches, make sure agents don't accidentally share one, clean them up when done, and then merge 10 branches back together, resolving the inevitable text-level conflicts along the way. It's fragile, expensive, and doesn't scale. At 20 agents it becomes unmanageable.
Even tools that try to automate worktree management can't hide the underlying complexity. To land a single small change, the automation has to: auto-stage untracked files, generate a commit message and commit, stash any in-progress changes in the main working directory (if present), merge the commit into main (checking whether a rebase is needed), restore the stashed changes, remove the worktree and its branch in the background, and switch back to the main worktree. That's 7+ orchestrated steps behind the scenes — any of which can fail — just to land one change from one agent. Multiply that by 20 agents working simultaneously and the house of cards collapses.
dkod replaces all of this with one atomic operation: SUBMIT. The agent sends a changeset, the platform verifies it, and merges it — in under 35 seconds. No worktrees, no stashing, no branch cleanup, no multi-step ceremony. Every agent connects to one codebase and gets a lightweight, isolated session — and the platform merges their work automatically because it understands code structure, not just text.
What is an AST?
An AST (Abstract Syntax Tree) is how a computer actually understands code. When you write a function, the compiler doesn't see lines of text — it sees a tree of meaningful pieces: "this is a function called login, it takes a username parameter, it calls validate() inside its body, and it returns a User."
Think of it like the difference between reading a book as a sequence of characters vs. understanding it as chapters, paragraphs, and sentences. Git sees characters. dkod sees the structure.
Text view (what Git sees): AST view (what dkod sees):
Line 1: fn login(user: &str) Function: login
Line 2: -> Result<User> { ├─ param: user (&str)
Line 3: let valid = validate( ├─ returns: Result<User>
Line 4: user └─ body:
Line 5: ); ├─ call: validate(user)
Line 6: Ok(User::new(valid)) └─ call: User::new(valid)
Line 7: }
When Git compares two versions of a file, it compares lines of text. If line 5 moved to line 6, Git sees a change — even if nothing meaningful changed. When dkod compares two versions, it compares structural elements. It knows login is a function, validate is a call inside it, and user is a parameter. If someone adds a blank line, dkod knows nothing actually changed.
This is why AST-level understanding is essential for multi-agent development. Agents make structural changes — adding functions, modifying parameters, updating call sites. An AST-aware platform can tell when two changes are truly independent, even if they happen in the same file.
How dkod Merging Works
dkod operates at the AST level. It doesn't compare lines of text — it compares structural code elements: functions, classes, types, imports, and their relationships.
Auto-Resolved: Different Symbols
Agent A: modifies authenticate_user() in auth.rs
Agent B: modifies reset_password() in auth.rs
The platform knows these are structurally independent changes. Different functions, no shared dependencies, no overlapping call sites. Automatic merge. No conflict.
Auto-Resolved: Compatible Changes
Agent A: adds a new parameter to User struct
Agent B: adds a different parameter to User struct
The platform detects that both changes add non-overlapping fields to the same struct. It merges them by combining both additions. No conflict.
Hard Conflict (True Semantic Conflict)
Agent A: deletes validate_session() function
Agent B: adds a new call to validate_session()
This is a hard conflict — Agent B depends on something Agent A removed. The platform detects this through the three-way AST merge and returns a structured ConflictBlock to the agent:
{
"status": "conflict",
"conflicting_symbols": [
{
"symbol": "validate_session",
"file": "src/auth/session.rs",
"base_version": "fn validate_session(token: &str) -> Result<Session>",
"their_change": {
"description": "Deleted function",
"change_type": "deleted"
},
"your_change": {
"description": "Added call in login_handler",
"change_type": "added_dependency"
}
}
],
"message": "Symbol 'validate_session' was deleted by another session but your changeset adds a dependency on it"
}The agent pauses, explains the conflict to the user with full context, and either resolves it programmatically or directs the user to the dashboard.
What Counts as a Conflict?
| Scenario | Git | dkod | Type |
|---|---|---|---|
| Two agents modify different functions in the same file | Conflict | Auto-merge | Auto-resolved |
| Two agents add different fields to the same struct | Conflict | Auto-merge | Auto-resolved |
| Two agents modify different sections of the same function | Conflict | Auto-merge (if non-overlapping AST nodes) | Auto-resolved |
| Two agents add the same import | Conflict | Deduplicate | Auto-resolved |
| Agent writes to a symbol another session already modified | N/A | Warning returned (write succeeds) | Soft conflict |
| Two agents modify the same function body | Conflict | Conflict (true conflict) | Hard conflict |
| Two agents add the same parameter | Conflict | Deduplicate | Auto-resolved |
| Agent A deletes a function that Agent B calls | No conflict (until runtime) | Conflict (caught at merge time) | Hard conflict |
Notice the last row: dkod actually catches more real conflicts than Git, because it understands dependencies. Git won't flag that a deleted function breaks another agent's code until the tests fail (if you're lucky).
Conflict Types
dkod uses a three-tier conflict model. Most concurrent changes are auto-resolved. Soft conflicts give agents early warnings. Hard conflicts are rare and surfaced with full context for fast resolution.
Auto-Resolved
When two agents modify different symbols in the same file — or make compatible changes to the same symbol (like adding non-overlapping struct fields) — dkod merges them automatically. No agent intervention, no human review, no delay.
This is the most common outcome. In typical multi-agent workloads, 90%+ of concurrent changes to the same file involve different functions and merge cleanly.
Soft Conflict (Write-Time Warning)
When an agent calls dk_file_write, the platform's SymbolClaimTracker checks whether another active session has already modified the same symbol. If it has, the write still succeeds — but the response includes a conflict_warnings array:
{
"new_hash": "a3f8c2...",
"detected_changes": [
{
"symbol_name": "authenticate_user",
"change_type": "modified"
}
],
"conflict_warnings": [
{
"file_path": "src/auth/handler.rs",
"symbol_name": "authenticate_user",
"conflicting_agent": "claude-code-v3",
"conflicting_session_id": "sess_x7y8z9",
"message": "Symbol 'authenticate_user' was already modified by claude-code-v3"
}
]
}Soft conflicts are early warnings, not blockers. They tell the agent: "another agent is working on the same symbol — you might want to coordinate before submitting." The agent can use WATCH to monitor the other session's progress or proactively adapt its approach.
Hard Conflict (Merge-Time)
When an agent calls dk_submit and the three-way AST merge detects that the same symbol was modified incompatibly by both the agent and another session that already merged — this is a hard conflict. The platform returns a ConflictBlock with full context:
- Base version — the common ancestor (what the symbol looked like before either agent touched it)
- Their change — what the other agent changed (already merged into HEAD)
- Your change — what this agent is trying to submit
- Resolution options —
proceed,keep_yours,keep_theirs,manual
The agent pauses execution, explains the conflict to the user with a summary of what each side changed, and presents the available resolution actions.
Resolution Actions
When a hard conflict is detected, four resolution actions are available:
proceed (recommended) — Unblocks the merge. The agent should then reconnect, re-read the updated code via dk_context, and re-submit its changeset. This preserves both agents' intent.
keep_yours — The agent's changes take priority for the conflicting symbols. The other agent's modifications to those specific symbols are overwritten. Non-conflicting changes from both agents are always preserved.
keep_theirs — The other agent's changes take priority. This agent's modifications to the conflicting symbols are discarded. Non-conflicting changes from both agents are always preserved.
manual — Provide custom resolution content for the conflicting symbols. Use this when neither version is correct and the conflict requires a hand-crafted merge.
In all cases, only the conflicting symbols are affected. If Agent A modified authenticate_user and reset_password, and only authenticate_user conflicts — reset_password is always preserved regardless of which resolution action is chosen.
Dashboard Resolution
Most true conflicts can be resolved directly from the MCP prompt — the agent receives the full ConflictBlock with base, theirs, and yours versions, and can proceed, keep_yours, keep_theirs, or manual without leaving the terminal.
But when you need a visual overview, the dkod web UI provides a changeset detail page. From the dashboard, users can:
- View the full three-way diff for each conflicting symbol (base, theirs, yours)
- See which agents made which changes and when
- Choose a resolution action with a single click
- Add review comments on specific lines

This is especially useful when the conflict requires human judgment — for example, when two agents made valid but architecturally incompatible decisions that need a human to choose the right direction.
The Semantic Code Graph
Semantic merging is powered by dkod's code graph — a structural representation of every codebase:
Symbol Table — every function, class, interface, type, variable, constant, module with name, kind, visibility, signature, and history.
Call Graph — who calls whom. Function A calls Function B, Module X imports Module Y, Class C implements Interface I, with complete transitive closure for impact analysis.
Dependency Graph — external packages with version pins, which symbols use which dependency, and vulnerability tracking.
Invariant Registry — rules that must hold across merges: "All public API endpoints must have auth middleware", "No function may exceed cyclomatic complexity of 20", and custom team-defined rules.
Dual Storage: Git + Semantic
dkod maintains both representations in sync:
┌──────────────────────────────────────────────┐
│ Code Storage Engine │
├─────────────────────┬────────────────────────┤
│ Git-Compatible │ Semantic Layer │
│ │ │
│ Blob objects │ AST graph per file │
│ Tree objects │ Symbol table │
│ Commit objects │ Call graph │
│ Pack files │ Dependency graph │
│ Refs │ Type information │
│ │ Semantic changesets │
│ │ │
│ For: Human CLI, │ For: Agent Protocol, │
│ backward compat │ semantic merging │
└─────────────────────┴────────────────────────┘
- Every standard Git operation updates the semantic layer
- Every Agent Protocol changeset updates the Git layer
- They are two views of the same underlying truth
This means you never lose Git compatibility. You can git clone, git push, and use your existing workflow at any time. The semantic merging layer works on top.
Performance
The semantic merge engine is built in Rust with incremental AST parsing — only changed files are re-parsed.
- Merge two compatible changesets: < 50ms
- Conflict detection: < 10ms
- Full semantic re-index after merge: < 500ms for typical repos
Next Steps
- Session Isolation — how agents work in parallel with isolated workspaces
- Agent Protocol — the six operations that power semantic merging
- Why dkod — the full comparison with Git and GitHub