This file is the single source of truth for any AI agent working on this project. Read this first before making changes.
A pure Swift Dev Tunnels client library for iOS/macOS. Client-side only — no host/server functionality.
Replaces the Rust FFI bridge approach (DevTunnelsBridge) with native Swift, eliminating cross-compilation, UniFFI binding generation, and dylib linking issues.
- Go SDK (best porting reference): microsoft/dev-tunnels — Go
- TypeScript SDK: microsoft/dev-tunnels — TypeScript
- Language: Swift (strict concurrency)
- Platforms: iOS 16+, macOS 13+
- Networking: URLSession (REST), NIO (WebSocket + SSH relay)
- SSH: SwiftNIO SSH
- Package manager: Swift Package Manager
dev-tunnels-swift/
├── AGENTS.md # This file
├── Decisions.md # Architectural decisions (append-only)
├── README.md # User-facing documentation
├── CONTRIBUTING.md # Contribution guidelines
├── CODE_OF_CONDUCT.md # Microsoft Open Source Code of Conduct
├── SECURITY.md # Security vulnerability reporting
├── Docs/ # Usage docs, tutorials
├── Specs/ # Pre-implementation specs, research
├── Package.swift # Swift Package manifest
├── .github/workflows/ # CI: swift build + swift test
├── Sources/DevTunnelsClient/
│ ├── Contracts/ # Types: Tunnel, TunnelEndpoint, TunnelPort, etc.
│ ├── Management/ # REST API client (full CRUD) + device code auth
│ └── Connections/ # Relay client (WebSocket → SSH → port forwarding)
└── Tests/DevTunnelsClientTests/
| Official SDK package | This library |
|---|---|
contracts |
Sources/DevTunnelsClient/Contracts/ |
management |
Sources/DevTunnelsClient/Management/ |
connections (client only) |
Sources/DevTunnelsClient/Connections/ |
| Feature | Status | Notes |
|---|---|---|
| List/Get tunnels | ✅ | REST API with region-scoped responses |
| Create/Update/Delete tunnels | ✅ | Full CRUD |
| Create/Delete tunnel ports | ✅ | Full CRUD |
| Device code auth (GitHub) | ✅ | OAuth device code flow |
| Direct connections | ✅ | URL generation for public ports |
| Relay connections | ✅ | WebSocket → SSH → port forwarding |
| Auto-reconnect | ✅ | Exponential backoff, configurable policy |
| WebSocket keepalive | ✅ | Periodic pings (30s default, configurable) |
| Server port notifications | ❌ | SSH tcpip-forward — not yet |
| Local TCP listener | ❌ | Caller handles local binding |
| Host-side functionality | ❌ | Out of scope (client-only) |
- Write a spec →
Specs/<feature>.mdwith goal, approach, edge cases, acceptance criteria - Log decisions → Append to
Decisions.md(never edit past entries) - Implement with tests → Every feature must have tests. All previous tests must pass.
- Commit → Small, atomic commits. One feature per commit.
- Contract tests: Codable encode/decode round-trips, JSON parsing from real API shapes
- Management tests: Protocol-based HTTP abstraction, mock responses, CRUD operations
- Auth tests: Mock device code flow responses
- Connection tests: NIO EmbeddedChannel for WebSocket/SSH pipeline, state machine
- Reconnection tests: Policy backoff math, state transitions, disconnect propagation
- Run:
swift test(155 tests, all offline)
- Use strict Swift concurrency (
Sendable,actor,async/await) - All public types must be
Sendable - All public APIs must have
///doc comments - Prefer
structfor value types,classwith@unchecked Sendableonly for NIO handlers - Use
protocolfor testable abstractions (HTTP client) - No force unwraps in production code
- No external dependencies except SwiftNIO family (for relay client)
swift build # Build
swift test # Run all tests (155 tests)