swift-tailscale-client 1.0.0 is the first stable release of the unofficial Swift client library and CLI for an already-installed Tailscale daemon.
This release adds safer configuration writes, bounded streaming, native macOS discovery, and a stable public API for monitoring apps and CLI automation. It is an independent project, not an official or endorsed Tailscale product.
Highlights
- Safe Serve & Funnel Configuration: Lossless
ServeConfigserialization with 64-bit integer precision; optimistic concurrency with mandatoryETagchecking prevents clobbering concurrent CLI or UI edits. Snapshots are bound to the original daemon target. - Hardened Wire Protocol & Transport Framing: Unconditional 64 KiB head limits, strict
Content-Lengthand chunked transfer framing, cooperative Task cancellation, and single-ownership descriptor cleanup (zero leaks over 100+ cycles). Transport accumulation is bounded. - Bounded Observable IPN Bus Streaming: Bounded queues with explicit
.stateGapdata loss reporting;StreamingResponsehead metadata delivery before body lines; classified exponential backoff with full jitter. - Native macOS Discovery: Zero-TCC discovery for macOS standalone
.pkgapps; opt-in App Store GUI discovery; non-blocking asynchronous probes; dynamic single-flight credential refresh on daemon restart. - Compatibility & Conformance: Public API compatibility/freeze checks, synthetic versioned fixtures, and 100% authored DocC coverage. Broader live-daemon conformance remains unqualified.
- In-Tree Consumer Simulation: Validated across simulated Network Weather (NWX) and TailscaleFleetAgent test suites using public APIs with zero
@testableimports. - Zero Third-Party Dependencies: Core library relies strictly on Foundation and POSIX APIs with zero external package dependencies.
Additional fixes
- Reject incomplete chunked streaming responses at EOF; verify lossless slow
consumption beyond the transport queue's high-water mark. - Collect exact-commit CI test reports and original logs for release validation,
including named skip reasons for the macOS unit and sanitizer lanes. - Fail soak verification when required measurements are unavailable, and test
failure verdicts through the actual harness.
Supported Platform & Daemon Matrix
- Runtime (Full LocalAPI Operations):
- macOS 13.0+ (Ventura, Sonoma, Sequoia) on
arm64andx86_64
- macOS 13.0+ (Ventura, Sonoma, Sequoia) on
- Outside 1.0 release qualification: Linux; no Linux binary or required build lane.
- Build-Only (Models, Types & Mocks): iOS 16.0+, tvOS 16.0+, watchOS 9.0+, visionOS 1.0+
- Swift Toolchain Minimum: Swift 6.1 (
swift-tools-version: 6.1); strict concurrency. - Tailscale Daemon Compatibility Target: 1.76.0 and later, subject to per-endpoint availability. This release does not claim a completed live-daemon version matrix.
Validation and limitations
- Apple CI: 879 tests in each of the macOS and Thread Sanitizer lanes, zero failures, 86.7% library line coverage; API freeze, strict DocC, and iOS/tvOS/watchOS builds passed. The 45 live-suite skips in each unit lane are explicitly recorded.
- NWX is the initial consumer. Its original event monitor and extracted client factory passed a focused local read-only smoke test; this is not a complete app trial.
- The self-hosted live-daemon runner was offline during qualification. A local read-only integration attempt had three connected-state assertion failures with the daemon stopped. A multi-version live matrix and sustained production soak remain incomplete; no daemon versions are certified by this release CI.
Breaking Changes (Migration from 0.12.x)
The 1.0.0 release includes 19 allowlisted API breaks to harden concurrency, resource management, and wire framing:
ServeConfigMutation API:setServeConfig(_:)now requires amatching: ServeConfigSnapshotparameter or explicit ETag. Calling with a missing or empty ETag throwsTailscaleClientError.missingConcurrencyToken.- Unconditional replacement must now call
replaceServeConfigUnconditionally(_:). - Model initializers (
ServeConfig,TCPPortHandler,WebServerConfig,HTTPHandler,ServiceConfig) updated to acceptunmodeledFields: [String: JSONValue].
- Streaming Response Signature:
TailscaleTransport.sendStreamingandURLSessionTailscaleTransport.sendStreamingnow returnStreamingResponserather thanAsyncThrowingStream<Data, Error>.MockTransport.StreamHandlerandscriptedStream/scriptedStreamsreturnStreamingResponseaccepting status codes and response headers.
- JSON Precision & Value Representation:
JSONValue.integernow wrapsInt64(changed fromInt) to guarantee 64-bit integer preservation without IEEE-754 precision loss.- Added new
JSONValue.unsignedInteger(UInt64)enum case.
- Profile Lifecycle API:
- Removed deprecated
addProfile(). UseswitchToEmptyProfile()(aligned with upstreamPUT /localapi/v0/profiles/).
- Removed deprecated
- Client Configuration & Discovery:
- Replaced legacy
TailscaleClientConfiguration.initwith dedicated initializers supportingEndpointSource(.automaticvs.pinned). TailscaleClientConfiguration.default(allowMacOSAppStoreDiscovery:)now accepts an optionaltransport:argument.
- Replaced legacy
- Typed Errors:
TailscaleClientErrorgained.missingConcurrencyToken,.streamOverflow, and.discovery(DiscoveryError)cases. Exhaustive switches must handle these cases.
Defect Closure Ledger (CL-01 to CL-12)
All 12 pre-1.0 and architectural review defects have been closed and verified by automated regression tests:
| ID | Originating Review | Defect Description | Severity | Resolution PR | Verifying Regression Test |
|---|---|---|---|---|---|
| CL-01 | Readiness Review | ServeConfig drops unmodeled root and nested JSON fields | High | PR 02 (5e6ddc7) |
ReadinessRegressionTests.testServeConfigPreservesUnknownRootAndNestedFields |
| CL-02 | Readiness Review | HTTPHeadBuffer accepts heads > 64 KiB when delimiter present | Critical | PR 04 (3be767b) |
ReadinessRegressionTests.testHTTPHeadExceeding64KiBFailsWithTypedMalformedResponseEvenWithDelimiter |
| CL-03 | Readiness Review | Incomplete chunked streams complete without terminal chunk | High | PR 04 (3be767b) |
ReadinessRegressionTests.testChunkedTransferUnaryRequiresCompletion |
| CL-04 | Readiness Review | Truncated Content-Length unary responses accepted as valid | High | PR 04 (3be767b) |
ReadinessRegressionTests.testContentLengthFramingEnforcedInUnaryResponse |
| CL-05 | Transport Audit | Socket connect blocks thread indefinitely without cancellation | High | PR 05 (f7ead04) |
UnixSocketFaultTests.testConnectCancellationResponsive |
| CL-06 | Transport Audit | Socket file descriptors leak across cancellation and errors | High | PR 05 (f7ead04) |
UnixSocketFaultTests.testDescriptorLeakFreeOver100Cycles |
| CL-07 | Streaming Audit | Streaming response head metadata invisible before body stream | Medium | PR 06 (be6bb42) |
StreamingTransportTests.testStreamingResponseDeliversHeaders |
| CL-08 | Streaming Audit | Unbounded IPN bus streaming buffer causes OOM under burst | High | PR 07 (7f9208f) |
IPNBusStreamingTests.testBoundedQueueEmitsStateGapOnOverflow |
| CL-09 | Streaming Audit | Producer task continues running after consumer stream cancellation | High | PR 07 (664d953) |
IPNBusStreamingTests.testProducerTaskCancelledOnStreamExit |
| CL-10 | Discovery Audit | Standalone .pkg app discovery fails or prompts for TCC | High | PR 08 (c8c50ec) |
LocalAPIDiscoveryTests.testStandaloneAppSymlinkDiscovery |
| CL-11 | Discovery Audit | Daemon restart invalidates loopback credentials permanently | High | PR 09 (182d239) |
DiscoveryRecoveryTests.testDaemonRestartRediscovery |
| CL-12 | API Audit | Deprecated addProfile() name diverges from upstream PUT |
Low | PR 13 (c4438b4) |
APICompatibilityTests.testAddProfileRemoval |
Documentation
- Added a detailed 1.0 implementation plan (
Documentation/PLAN-1.0.md) with work-item dependencies, a reviewable PR sequence, acceptance tests, exact-commit release gates, consumer validation, and upstream adoption preparation. - Recorded 1.0 public contract decisions in
Documentation/DECISIONS-1.0.md(safe Serve writes with concurrency snapshots, streaming response metadata, bounded IPN bus lifecycle, automatic vs pinned discovery credential refresh, experimental API source compatibility, netcheck scope, and supported environments). - Defined official 1.0 platform, toolchain, and daemon compatibility matrix in
Documentation/SUPPORT.md. - Authored 100% DocC documentation coverage with
--warnings-as-errorsacross all public types and members. - Authored complete soak verification protocol and test record in
Documentation/SOAK-VERIFICATION.md. - Added a template for a future production consumer evaluation in
Documentation/CONSUMER-EVALUATION-REPORT.md. - Authored 1.0.0 release evidence record in
Documentation/releases/1.0.0.md.
Added
- Added
ReadinessRegressionTestscovering pre-1.0 readiness review findings: unknown ServeConfig field drops, HTTP head size limit bypass with delimiter present, unvalidated chunked decoder completion, and unvalidated Content-Length framing. - Implemented
run-soak-verification.pystandalone soak test harness supporting accelerated and extended verification modes with kernel resource introspection.