Successor to the Tunnels portion of #2. The embedding-retrieval portion of #2 is superseded by #8 (Qdrant + nomic-embed-text), which is the project's chosen vector backend per DECISIONS.md 2026-04-08.
This issue scopes only to cross-Wing concept linking — making the same concept discoverable from any Wing it appears in, without rebuilding retrieval.
Depends on #1 (Hall taxonomy) — Wing/Hall path layout must exist for tunnels to be meaningful.
Problem
The same concept can appear in multiple Wings (e.g. pex-copper in both bathroom-plumbing and koala-plumbing, or val-vol-r2 in both jepa-fx and hyperguild). Current retrieval treats Wings as isolated silos. There is no way to ask "what do I know about X across all Wings?" and get a navigable cross-Wing path.
Design
A Tunnel is a bidirectional wikilink between two notes in different Wings that share a concept. Two creation paths:
Automatic — when brain_write writes a note with wing=A, run a lightweight concept-match pass over the new note's content against an in-memory index of existing Wing names and note titles. On exact match in Wing B, append a ## See also section to the new note with a wikilink to the matched note in Wing B, and append a reciprocal link to that note.
Manual — new MCP tool brain_tunnel taking source (wing/hall/slug) and target (wing/hall/slug) writes the bidirectional link explicitly.
Tunnels are plain Obsidian wikilinks ([[wing-b/hall/slug]]) — no special syntax, no database. Obsidian's graph view shows cross-wing edges naturally.
Fuzzy auto-matches (not exact) land in brain/raw/tunnel-candidates-<date>.md for human review, never written automatically.
Implementation
ingestion/internal/brain/tunnel.go
packagebraintypeTunnelCandidatestruct{SourcePathstringTargetPathstringMatchedTermstring}// DetectTunnels scans brainDir/wiki/ for notes whose titles overlap with// terms extracted from content. Returns candidates without writing.funcDetectTunnels(brainDir,contentstring)([]TunnelCandidate,error)// WriteTunnel appends a wikilink to both source and target notes.// Idempotent — does not duplicate if link already present.funcWriteTunnel(brainDir,sourcePath,targetPathstring)error
New MCP tool: brain_tunnel
{"name":"brain_tunnel","description":"Create an explicit bidirectional link between two notes in different wings.","parameters":{"source":"wing/hall/slug of the source note","target":"wing/hall/slug of the target note"}}
Auto-tunnel hook in brain_write
After every brain_write with wing+hall, run DetectTunnels over the new content. Exact title matches → write bidirectional link. Fuzzy candidates → append to brain/raw/tunnel-candidates-<YYYY-MM-DD>.md.
Acceptance criteria
brain_tunnel source=jepa-fx/decisions/val-vol-r2 target=hyperguild/decisions/routing-floor writes wikilinks in both files and is idempotent on second call
Auto-tunnel after brain_write creates a link when an exact Wing/note title match is found in content
Fuzzy candidates land in brain/raw/tunnel-candidates-<date>.md, not written automatically
Obsidian graph view shows cross-wing edges for tunnel links
## Context
Successor to the Tunnels portion of #2. The embedding-retrieval portion of #2 is superseded by #8 (Qdrant + nomic-embed-text), which is the project's chosen vector backend per DECISIONS.md 2026-04-08.
This issue scopes only to **cross-Wing concept linking** — making the same concept discoverable from any Wing it appears in, without rebuilding retrieval.
Depends on #1 (Hall taxonomy) — Wing/Hall path layout must exist for tunnels to be meaningful.
## Problem
The same concept can appear in multiple Wings (e.g. `pex-copper` in both `bathroom-plumbing` and `koala-plumbing`, or `val-vol-r2` in both `jepa-fx` and `hyperguild`). Current retrieval treats Wings as isolated silos. There is no way to ask "what do I know about X across all Wings?" and get a navigable cross-Wing path.
## Design
A Tunnel is a bidirectional wikilink between two notes in different Wings that share a concept. Two creation paths:
**Automatic** — when `brain_write` writes a note with `wing=A`, run a lightweight concept-match pass over the new note's content against an in-memory index of existing Wing names and note titles. On exact match in Wing B, append a `## See also` section to the new note with a wikilink to the matched note in Wing B, and append a reciprocal link to that note.
**Manual** — new MCP tool `brain_tunnel` taking `source` (wing/hall/slug) and `target` (wing/hall/slug) writes the bidirectional link explicitly.
Tunnels are plain Obsidian wikilinks (`[[wing-b/hall/slug]]`) — no special syntax, no database. Obsidian's graph view shows cross-wing edges naturally.
Fuzzy auto-matches (not exact) land in `brain/raw/tunnel-candidates-<date>.md` for human review, never written automatically.
## Implementation
### `ingestion/internal/brain/tunnel.go`
```go
package brain
type TunnelCandidate struct {
SourcePath string
TargetPath string
MatchedTerm string
}
// DetectTunnels scans brainDir/wiki/ for notes whose titles overlap with
// terms extracted from content. Returns candidates without writing.
func DetectTunnels(brainDir, content string) ([]TunnelCandidate, error)
// WriteTunnel appends a wikilink to both source and target notes.
// Idempotent — does not duplicate if link already present.
func WriteTunnel(brainDir, sourcePath, targetPath string) error
```
### New MCP tool: `brain_tunnel`
```json
{
"name": "brain_tunnel",
"description": "Create an explicit bidirectional link between two notes in different wings.",
"parameters": {
"source": "wing/hall/slug of the source note",
"target": "wing/hall/slug of the target note"
}
}
```
### Auto-tunnel hook in `brain_write`
After every `brain_write` with `wing`+`hall`, run `DetectTunnels` over the new content. Exact title matches → write bidirectional link. Fuzzy candidates → append to `brain/raw/tunnel-candidates-<YYYY-MM-DD>.md`.
## Acceptance criteria
- `brain_tunnel source=jepa-fx/decisions/val-vol-r2 target=hyperguild/decisions/routing-floor` writes wikilinks in both files and is idempotent on second call
- Auto-tunnel after `brain_write` creates a link when an exact Wing/note title match is found in content
- Fuzzy candidates land in `brain/raw/tunnel-candidates-<date>.md`, not written automatically
- Obsidian graph view shows cross-wing edges for tunnel links
- `task check` passes
## Out of scope
- Embedding-based retrieval — moved to #8
- Automatic creation for fuzzy matches — human review required
- Obsidian plugin development
## Dependencies
- #1 (Hall taxonomy) must merge first
Shipped in ddd07ae. TDD all the way: each helper landed RED → GREEN with regression tests.
Acceptance criteria
brain_tunnel source=jepa-fx/decisions/val-vol target=hyperguild/decisions/routing writes wikilinks in both files; re-call is a no-op (idempotency test asserts link count = 1 after 3 calls)
Auto-tunnel after brain_write creates a link when an exact wing/note-title match is found in content (TestBrainWriteAutoTunnelsOnExactMatch)
Same-wing matches are NOT auto-linked (TestBrainWriteAutoTunnelSkipsSameWing)
Fuzzy candidates land in brain/raw/tunnel-candidates-<date>.md, not written automatically (TestAutoTunnel_FuzzyGoesToCandidatesFile)
Obsidian graph view sees [[wing/hall/slug]] wikilinks under ## See also
brain_tunnel(source, target) — manual cross-wing link
brain_write with wing+hall now runs AutoTunnel after the write
Slug-fallback titles humanise (widget-flags → widget flags) so titleless notes still participate in matching.
Live deploy
CI/CD picks up ddd07ae automatically. Live brain MCP will expose the new tool after the routing-pod-style ingestion image rebuild lands in infra.
Closing.
Shipped in `ddd07ae`. TDD all the way: each helper landed RED → GREEN with regression tests.
### Acceptance criteria
- [x] `brain_tunnel source=jepa-fx/decisions/val-vol target=hyperguild/decisions/routing` writes wikilinks in both files; re-call is a no-op (idempotency test asserts link count = 1 after 3 calls)
- [x] Auto-tunnel after `brain_write` creates a link when an exact wing/note-title match is found in content (`TestBrainWriteAutoTunnelsOnExactMatch`)
- [x] Same-wing matches are NOT auto-linked (`TestBrainWriteAutoTunnelSkipsSameWing`)
- [x] Fuzzy candidates land in `brain/raw/tunnel-candidates-<date>.md`, not written automatically (`TestAutoTunnel_FuzzyGoesToCandidatesFile`)
- [x] Obsidian graph view sees `[[wing/hall/slug]]` wikilinks under `## See also`
- [x] `task check` green
### Surface added
```go
// ingestion/internal/brain
type TunnelCandidate struct{ TargetPath, MatchedTerm string; Exact bool }
func WriteTunnel(brainDir, source, target string) error
func DetectTunnels(brainDir, content string) ([]TunnelCandidate, error)
func AutoTunnel(brainDir, source, content string) error
```
MCP additions:
- `brain_tunnel(source, target)` — manual cross-wing link
- `brain_write` with wing+hall now runs `AutoTunnel` after the write
Slug-fallback titles humanise (`widget-flags` → `widget flags`) so titleless notes still participate in matching.
### Live deploy
CI/CD picks up `ddd07ae` automatically. Live brain MCP will expose the new tool after the routing-pod-style ingestion image rebuild lands in infra.
Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Context
Successor to the Tunnels portion of #2. The embedding-retrieval portion of #2 is superseded by #8 (Qdrant + nomic-embed-text), which is the project's chosen vector backend per DECISIONS.md 2026-04-08.
This issue scopes only to cross-Wing concept linking — making the same concept discoverable from any Wing it appears in, without rebuilding retrieval.
Depends on #1 (Hall taxonomy) — Wing/Hall path layout must exist for tunnels to be meaningful.
Problem
The same concept can appear in multiple Wings (e.g.
pex-copperin bothbathroom-plumbingandkoala-plumbing, orval-vol-r2in bothjepa-fxandhyperguild). Current retrieval treats Wings as isolated silos. There is no way to ask "what do I know about X across all Wings?" and get a navigable cross-Wing path.Design
A Tunnel is a bidirectional wikilink between two notes in different Wings that share a concept. Two creation paths:
Automatic — when
brain_writewrites a note withwing=A, run a lightweight concept-match pass over the new note's content against an in-memory index of existing Wing names and note titles. On exact match in Wing B, append a## See alsosection to the new note with a wikilink to the matched note in Wing B, and append a reciprocal link to that note.Manual — new MCP tool
brain_tunneltakingsource(wing/hall/slug) andtarget(wing/hall/slug) writes the bidirectional link explicitly.Tunnels are plain Obsidian wikilinks (
[[wing-b/hall/slug]]) — no special syntax, no database. Obsidian's graph view shows cross-wing edges naturally.Fuzzy auto-matches (not exact) land in
brain/raw/tunnel-candidates-<date>.mdfor human review, never written automatically.Implementation
ingestion/internal/brain/tunnel.goNew MCP tool:
brain_tunnelAuto-tunnel hook in
brain_writeAfter every
brain_writewithwing+hall, runDetectTunnelsover the new content. Exact title matches → write bidirectional link. Fuzzy candidates → append tobrain/raw/tunnel-candidates-<YYYY-MM-DD>.md.Acceptance criteria
brain_tunnel source=jepa-fx/decisions/val-vol-r2 target=hyperguild/decisions/routing-floorwrites wikilinks in both files and is idempotent on second callbrain_writecreates a link when an exact Wing/note title match is found in contentbrain/raw/tunnel-candidates-<date>.md, not written automaticallytask checkpassesOut of scope
Dependencies
Shipped in
ddd07ae. TDD all the way: each helper landed RED → GREEN with regression tests.Acceptance criteria
brain_tunnel source=jepa-fx/decisions/val-vol target=hyperguild/decisions/routingwrites wikilinks in both files; re-call is a no-op (idempotency test asserts link count = 1 after 3 calls)brain_writecreates a link when an exact wing/note-title match is found in content (TestBrainWriteAutoTunnelsOnExactMatch)TestBrainWriteAutoTunnelSkipsSameWing)brain/raw/tunnel-candidates-<date>.md, not written automatically (TestAutoTunnel_FuzzyGoesToCandidatesFile)[[wing/hall/slug]]wikilinks under## See alsotask checkgreenSurface added
MCP additions:
brain_tunnel(source, target)— manual cross-wing linkbrain_writewith wing+hall now runsAutoTunnelafter the writeSlug-fallback titles humanise (
widget-flags→widget flags) so titleless notes still participate in matching.Live deploy
CI/CD picks up
ddd07aeautomatically. Live brain MCP will expose the new tool after the routing-pod-style ingestion image rebuild lands in infra.Closing.