4.5 KiB
Conduit — Agent Guidelines
Project Overview
Conduit is a self-hosted tunneling service (Go, single binary). A server (conduit serve) runs on a public host and routes incoming HTTP requests by subdomain to registered tunnels. A client (conduit tunnel) connects via WebSocket, receives forwarded traffic, and relays it to a local target using either an HTTP reverse-proxy or raw TCP dial.
Build & Test
# Build all platforms
make build_local
# Run tests
make tests # includes race detection + coverage
# Lint
golangci-lint run
Go 1.25+ is required (go.mod). Nix devshell provides Go, gopls, golangci-lint.
Architecture at a Glance
server/server.go — net/http.Server, ServeHTTP routes by Host subdomain to tunnel or control API
tunnel/tunnel.go — Core Tunnel struct, WebSocket message loop, stream management
tunnel/forwarder.go — Forwarder interface; HTTP/HTTPS → HTTP forwarder, everything else → TCP
tunnel/http_forwarder.go — httputil.ReverseProxy served over net.Pipe via multiConnListener
tunnel/tcp_forwarder.go — Direct net.Dial TCP forwarding
tunnel/stream.go — Stream interface (io.ReadWriteCloser + Source/Target)
server/reconstructed_conn.go — Replays re-serialized headers + buffered body + raw conn after hijack
store/store.go — In-memory request/response recorder with pub/sub (SSE)
web/web.go — Local tunnel monitor (port 8181), SSE endpoint
config/config.go — Reflection-based config from struct tags → flags + env vars + client config file
pkg/maps/map.go — Generic sync.RWMutex-guarded map
Code Conventions
- Go style: standard
gofmt, golangci-lint with.golangci.toml - Comment style: Title Case heading above logical blocks (see root
AGENTS.md) - Config: add struct tags (
json,default,description) toServerConfigorClientConfig— flags and env vars are auto-derived. Client config may also come from./conduit.jsonor~/.config/conduit/config.jsonforserver,api_key,log_level, andlog_formatonly. - Logging: use
logrus(logalias); structured fields preferred - Concurrency: use
pkg/maps.Mapfor shared maps; protect other shared state withsync.Mutex - Error handling: return errors up; log at command/entry-point level. Use
fmt.Errorfwith%wfor wrapping
Key Patterns
- ServeHTTP + Hijack for tunnel routing: The server uses
net/http.Serverwith aServeHTTPhandler. It inspects theHostheader to determine routing. Control API requests are handled normally viahttp.ResponseWriter. Tunnel requests hijack the TCP connection, re-serialize the HTTP request, and forward it through the tunnel viareconstructedConn. - Reconstructed connection: After hijack,
reconstructedConncombines re-serialized request headers, buffered body data from the hijackedbufio.ReadWriter, and the raw connection into a singleio.Readerso the tunnel client receives the complete request. - Forwarder abstraction:
Forwarderinterface decouples tunnel transport from protocol handling.NewForwarderonly usesurl.Parseforhttp:///https://schemes; everything else (including parse failures like barehost:port) is treated as raw TCP. HTTP forwarder usesnet.Pipe+multiConnListenerto feed connections into a standardhttp.Server. - Context-threaded records: Request records are attached to context in
RecordRequestand retrieved inRecordResponsevia theModifyResponsehook.
Adding a New Forwarder
- Implement
tunnel.Forwarderinterface (Type(),Initialize(),Start()) - Add a case in
tunnel.NewForwarder()factory - Add corresponding
ForwarderTypeconst
Testing
E2E tests live in e2e_test.go at the project root. They spin up real servers, tunnels, and targets on random ports. make tests runs with -race and coverage enabled.
# Run all tests
make tests
# Run specific test
go test -v -run TestHTTPTunnelRoundTrip -count=1 ./...
16 tests covering: HTTP round-trip (GET/POST), TCP echo, large bodies (1MB resp / 512KB req), response quality (headers, content-type, content-length), error paths (404, 401, duplicate name), multi-tunnel routing, concurrency, and graceful shutdown.
File Locations
| Concern | Files |
|---|---|
| CLI entry | main.go, cmd/ |
| Server | server/ |
| Tunneling | tunnel/ |
| Config | config/ |
| Storage | store/ |
| Web UI | web/, web/pages/ |
| Shared types | types/ |
| Utilities | pkg/maps/ |
| E2E tests | e2e_test.go |