docs: scaffold Sidecar repo with architecture and protocol drafts#1
Draft
firenzemc wants to merge 3 commits into
Draft
docs: scaffold Sidecar repo with architecture and protocol drafts#1firenzemc wants to merge 3 commits into
firenzemc wants to merge 3 commits into
Conversation
Sidecar is a lightweight Tailscale-network device dashboard for macOS, built around desktop widgets and a Grafana-lite system metrics view. This first commit lands only the design docs so the agent and macOS app can be built against a stable shape. - README explains the project's motivation, structure, and roadmap. - docs/architecture.md covers the Go agent (binds tailscale0, depends on host tailscaled), the SwiftUI + WidgetKit Mac app (peer discovery, poller, App Group shared store, theme system), and security boundaries. - docs/protocol.md drafts the v0 JSON contract for /healthz, /info, and /metrics, with field semantics, nullability rules, and a forward- compatibility policy.
First working cut of sidecar-agent (M1). Single Go binary, no CGO, builds
clean for darwin/arm64, darwin/amd64, linux/amd64, windows/amd64.
Identifies the Tailscale interface by IP range (CGNAT 100.64/10 for v4,
fd7a:115c:a1e0::/48 for v6) rather than name, so it works regardless of
whether the OS named it tailscale0, utun*, or "Tailscale". Binds only to
those addresses; refuses to fall back to 0.0.0.0. A --bind override is
provided for local dev without Tailscale.
Endpoints match docs/protocol.md v0.1:
- GET /healthz → plain "ok"
- GET /info → agent / host / tailnet / capabilities
- GET /metrics → 1s-rolling snapshot of CPU, mem, load (POSIX only),
disks (≥1 GiB), and per-NIC rx/tx bps + totals.
A background goroutine samples once per second, holds the latest snapshot
in an atomic pointer, and HTTP handlers read it without blocking the
sampler. Net rates are deltas computed from the previous tick.
X-Sidecar-Agent: v0.1 protocol header is emitted on every response so the
Mac client can refuse to talk to a major-bumped agent.
First cut of sidecar-mac (M2). Targets macOS 14, no third-party runtime
deps. The .xcodeproj is generated from project.yml via XcodeGen — run
`xcodegen generate` on first checkout and the file is gitignored.
Architecture mirrors docs/architecture.md:
- Models/ — Device + DeviceState (runtime) and AgentDTO (Codable types
matching docs/protocol.md exactly, with snake_case CodingKeys and a
custom JSONDecoder that handles RFC 3339 with optional fractional
seconds, since the agent emits both forms).
- Services/TailscaleCLI — `Process` wrapper; resolves the binary from
/usr/local/bin, /opt/homebrew/bin, and inside Tailscale.app. Decodes
only the small subset of `tailscale status --json` we actually need
(Self + Peer.{ID, HostName, DNSName, OS, TailscaleIPs, Online}) so
Tailscale schema drift mostly doesn't break us.
- Services/PeerDiscovery — combines tailscale CLI with parallel
/healthz probes (TaskGroup) at the agent's default 8765.
- Services/AgentClient — async URLSession wrapper for /info /metrics;
rejects responses whose X-Sidecar-Agent header isn't on the v0 line.
- Services/Poller — actor running a periodic /metrics fan-out and
reporting back via an async callback.
- Services/MockData — deterministic mock devices and snapshots for
designing the UI without a tailnet (and for screenshots).
- ViewModel/DashboardModel — @observable @mainactor source of truth.
Switching DataSource.live <-> .mock tears down and rebuilds discovery
/ poller / mock task cleanly.
- Views/GridOverview — adaptive LazyVGrid with a Canvas-drawn dotted
backdrop (only when theme.showsGridBackdrop is true).
- Views/DeviceCard — hostname, OS glyph, online dot with glow, CPU/MEM
bars, mini RX/TX rate readout. Shows "no agent" / error states.
- Theme/Theme.swift — three themes (Grid / Phosphor / Glass) plus
shared Tokens for corner radius, spacing, and monospaced fonts.
App Sandbox is intentionally disabled because we shell out to the
`tailscale` binary; macapp/README documents the trade-off and possible
future paths (LocalAPI socket or privileged helper). Suitable for v0
since distribution is direct, not Mac App Store.
Code is written but unverified — I'm developing in a Linux sandbox and
have no Swift toolchain available, so the commit may fail to compile on
first try and need small fixes once opened in Xcode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
起步提交,落地 Sidecar 项目的设计文档(暂不含代码)。Sidecar 的目标是给 Tailscale 网络里的多设备做一个 macOS 原生、widget 优先的轻量监控面板 —— 比 Grafana 全家桶更克制,但比纯 ping 状态多看到 CPU / 内存 / 流量等指标。
本 PR 仅包含文档:
tailscale0、依赖宿主 tailscaled)、SwiftUI + WidgetKit Mac app 模块划分(PeerDiscovery / Poller / App Group SharedStore / Theme 系统)、安全边界/healthz、/info、/metrics),字段语义、可空规则、向前兼容策略Key decisions captured
tailscale0监听 :8765,不绑 0.0.0.0tailscale status --json列 peer,按约定端口探活whoisTest plan
文档 PR,不涉及构建或测试。
Generated by Claude Code