Inspiration

Hackathons move fast. You’re constantly sending files, screenshots, and quick context updates while coding in parallel. The usual “fast” collaboration tools under time pressure come with tradeoffs:

  • public-by-default links
  • accounts and permission setup
  • port forwarding / exposing local services
  • too much overhead for a weekend

We wanted something smaller and sharper: a tiny workspace for two devices—chat + file drops + “send this screenshot right now”—but private by design.

When we saw the Tailscale challenge prompt, we realized the cleanest solution wasn’t to bolt security onto collaboration—it was to make collaboration a tailnet-only service where ACLs are the security boundary.

That’s why we built tailSync: a secure mini-workspace built on your tailnet.


What it does

tailSync creates a shared workspace between exactly two devices on a Tailscale tailnet.

Core features

1) Realtime chat

  • Instant messaging between host and joiner
  • Timestamps + sender identity

2) File sharing

  • Upload any file to the host workspace
  • The other device instantly sees it in the feed and can download it

3) Screenshot → shared feed

  • One-click screenshot capture (with optional caption)
  • Posted as an image card in the workspace feed, in real time

4) Connection panel

  • Shows Host/Join status, workspace code, and connection details
  • Clear error if blocked: “Blocked by Tailscale ACL or not on tailnet.” tailSync does not rely on a public backend. The workspace is a private service:
  • Host service runs locally
  • Published to a tailnet HTTPS URL via Tailscale Serve
  • Join happens only via HTTPS/WSS over the tailnet
  • ACLs determine whether the joiner is allowed

Challenges we ran into...

1) Making Tailscale truly essential We avoided the common hackathon path (public server + “also Tailscale”). Instead:

  • host service stays localhost-only
  • Serve URL is the only join path
  • ACLs control access, not app-level auth

2) Clear UX when ACL blocks An ACL denial can look like a network timeout. We built explicit error messaging so the demo is understandable:

“Blocked by Tailscale ACL or not on tailnet.”

3) Realtime correctness We kept the realtime protocol simple:

  • WebSocket broadcasts for chat, post:new, presence
  • HTTP endpoints for file upload/download and feed refresh

Accomplishments that we're proud of

  • Tailscale demo: tailnet + ACL enforcement + Serve URL required
  • Instant collaboration loop: screenshot → upload → appears on other device in realtime
  • No external backend: the workspace is private and self-hosted
  • Clear architecture + demo story: judges can see exactly why Tailscale matters

What's next for tailSync

  • Add Tailscale identity-aware join (auto label users using tailnet identity)
  • Add role-based permissions derived from tailnet groups (host/admin vs viewer)
  • Add a persistent side panel mode and keyboard shortcuts
  • Add lightweight encryption at rest for uploaded files

Built with

  • Client: Electron + React (Vite), TailwindCSS, OS Snipping integration, notch toolbar overlay
  • Backend: Node.js, TypeScript, Express, ws, multer
  • Infra: Tailscale Serve (required), Tailscale ACLs (required) for access control

Built With

Share this project:

Updates