Skip to content

docs: scaffold Sidecar repo with architecture and protocol drafts#1

Draft
firenzemc wants to merge 3 commits into
mainfrom
claude/tailscale-monitoring-dashboard-xKcON
Draft

docs: scaffold Sidecar repo with architecture and protocol drafts#1
firenzemc wants to merge 3 commits into
mainfrom
claude/tailscale-monitoring-dashboard-xKcON

Conversation

@firenzemc

Copy link
Copy Markdown
Owner

Summary

起步提交,落地 Sidecar 项目的设计文档(暂不含代码)。Sidecar 的目标是给 Tailscale 网络里的多设备做一个 macOS 原生、widget 优先的轻量监控面板 —— 比 Grafana 全家桶更克制,但比纯 ping 状态多看到 CPU / 内存 / 流量等指标。

本 PR 仅包含文档:

  • README.md — 项目背景、整体架构、仓库结构、roadmap、非目标
  • docs/architecture.md — Go agent 设计(绑定 tailscale0、依赖宿主 tailscaled)、SwiftUI + WidgetKit Mac app 模块划分(PeerDiscovery / Poller / App Group SharedStore / Theme 系统)、安全边界
  • docs/protocol.md — agent ↔ app 的 v0 JSON 协议草案(/healthz/info/metrics),字段语义、可空规则、向前兼容策略
  • .gitignore — Xcode / SwiftPM / Go 常规忽略

Key decisions captured

  • Tech stack — SwiftUI + WidgetKit 原生 app + Go 单二进制 agent
  • Tailnet 接入 — agent 依赖宿主机已装的 tailscaled,只在 tailscale0 监听 :8765,不绑 0.0.0.0
  • 发现机制 — 主 app 调用本地 tailscale status --json 列 peer,按约定端口探活
  • 数据流 — pull 模型,主 app 轮询 → App Group 共享容器 → widget TimelineProvider 节流读
  • 认证 — v0 信任 tailnet ACL,不做应用层鉴权;后续可基于 Tailscale whois

Test plan

文档 PR,不涉及构建或测试。

  • 本地通读 README / architecture / protocol 一致性
  • reviewer 确认架构决策(agent 接入方式、协议形状)后开 M1 agent 骨架

Generated by Claude Code

claude added 3 commits May 8, 2026 12:38
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants