Skip to content

alfonsopuicercus/source-relay

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SourceRelay logo

SourceRelay

A private macOS bridge that turns Calendar, Things 3, and Obsidian into one clean local API for personal dashboards.

Permission-first. Local by default. Dashboard-ready.

SourceRelay is a native macOS app for people who run personal dashboards and want those dashboards to talk to the apps where their real context lives. It collects upcoming events, tasks, and selected notes into a normalized snapshot, exposes a small authenticated HTTP API, and includes a diagnostics dashboard so you can see exactly what the bridge is serving.

The app is designed to replace one-off scripts and terminal-launched bridge servers with a launchable macOS app: Dock icon, menu bar status, source access controls, saved ports, and a UI for checking whether the bridge is healthy.

Screenshots

The screenshots below show the native app window, the permission setup flow, the saved bridge configuration, and the compact menu bar status panel. The Obsidian vault path is intentionally hidden in the public screenshot.

Overview Sources
SourceRelay overview showing bridge health, item counts, and endpoints SourceRelay Sources tab showing Calendar, Things, and Obsidian access controls
Bridge Settings Menu Bar
SourceRelay Bridge tab showing editable host, API port, diagnostics port, save button, and write toggles SourceRelay menu bar popup showing sync status and quick actions

What It Does

  • Reads upcoming Calendar events.
  • Reads Things 3 tasks by tag, area, project, date window, pin, or hide state.
  • Reads selected Obsidian Markdown tasks and notes from a user-chosen vault.
  • Normalizes everything into a single Bridge API v1 snapshot.
  • Lets dashboards pin or hide items without changing the original source.
  • Keeps writes disabled by default, with per-source write toggles.
  • Serves a local diagnostics UI with countdown cards, source counts, overrides, Obsidian items, and raw item inspection.
  • Saves bridge host, API port, diagnostics port, vault path, source rules, and write settings between launches.

Safety Model

SourceRelay is intended for private use on your Mac or trusted private network. Do not expose it directly to the public internet.

  • The API requires an authorization credential copied from the app.
  • The credential is stored in the macOS Keychain when possible.
  • Settings are stored at ~/Library/Application Support/SourceRelay/settings.json with private file permissions.
  • The diagnostics UI binds to loopback.
  • Source writes are off by default.
  • Calendar, Things 3, and Obsidian access are granted from the native app UI.

Requirements

  • macOS 14 or newer.
  • Xcode Command Line Tools or Xcode.
  • Swift toolchain compatible with the package.
  • Optional sources:
    • Apple Calendar.
    • Things 3.
    • An Obsidian vault stored on local disk or a synced folder.

Install Xcode Command Line Tools if needed:

xcode-select --install

Quick Start

Clone and build the app:

git clone https://github.com/alfonsopuicercus/source-relay.git
cd source-relay
mac_app/scripts/package_app.sh
open mac_app/build/SourceRelay.app

On first launch:

  1. Open the SourceRelay window from the Dock or menu bar.
  2. Go to Sources.
  3. Click Allow Calendar Access if you want calendar events.
  4. Click Allow Things Automation if you want Things 3 tasks.
  5. Click Choose Vault if you want Obsidian items.
  6. Go to Bridge.
  7. Choose the API host and ports.
  8. Click Save Settings.
  9. Go to Overview and click Start Bridge or Restart Bridge.
  10. Click Open Diagnostics to confirm data is flowing.

Daily Use

Once configured, SourceRelay is meant to stay out of the way:

  1. Launch SourceRelay.app.
  2. Check the menu bar icon: green means the bridge is serving data.
  3. Use Sync Now from the menu bar when you want an immediate refresh.
  4. Use Open Dashboard to inspect the diagnostics UI.
  5. Keep your personal dashboard pointed at the stable Bridge API URL.

Pin and hide actions from your dashboard call the Bridge API and are stored by SourceRelay as local overrides. They do not delete or rewrite the original Calendar, Things, or Obsidian item.

Download Options

Use one of these paths:

  • GitHub Releases: download the packaged app zip when a release is available.
  • Build from source: run mac_app/scripts/package_app.sh.
  • Source archive: use GitHub's Code → Download ZIP button.

If macOS warns that the app is from an unidentified developer, open it with right-click → Open. The app is not notarized unless you sign and notarize your own build.

Configuration

Open Bridge in the app to edit and save these values:

Setting Typical value Notes
API Host 127.0.0.1 Local-only dashboard on the same Mac.
API Host 0.0.0.0 Dashboard on another trusted device in your private network.
API Port 8765 Main Bridge API port.
Diagnostics Port 8766 Browser diagnostics UI.
Things writes Off Enables Things mutations only when switched on.
Calendar writes Off Enables Calendar mutations only when switched on.
Obsidian writes Off Enables Obsidian mutations only when switched on.

Click Save Settings after editing host or ports. Restart the bridge for port changes to take effect.

Environment variables can override saved values for advanced launches:

SOURCE_RELAY_API_HOST=127.0.0.1 \
SOURCE_RELAY_API_PORT=8765 \
SOURCE_RELAY_DIAGNOSTICS_PORT=8766 \
open mac_app/build/SourceRelay.app

Dashboard Integration

Point your dashboard at:

http://<mac-host>:8765/v1

Use the credential from Copy API Credential:

export SOURCE_RELAY_TOKEN="<copied-token>"

curl \
  -H "Authorization: Bearer ${SOURCE_RELAY_TOKEN}" \
  http://127.0.0.1:8765/v1/health

curl \
  -H "Authorization: Bearer ${SOURCE_RELAY_TOKEN}" \
  http://127.0.0.1:8765/v1/snapshot

For a dashboard running on another device:

  1. Set SourceRelay API Host to 0.0.0.0.
  2. Keep the API Port stable, for example 8765.
  3. Use the Mac's private network hostname or IP in the dashboard.
  4. Use the copied API credential in the dashboard configuration.
  5. Keep diagnostics local unless you explicitly proxy it for yourself.

Bridge API v1

All routes require:

Authorization: Bearer <copied-token>

Routes:

Method Route Purpose
GET /v1 API metadata and route list.
GET /v1/health Minimal health check.
GET /v1/snapshot Current selected items, all items, rules, errors, and overrides.
POST /v1/refresh Re-read sources and return a new snapshot.
GET /v1/search?q=term Search normalized items.
GET /v1/rules Read current selection rules.
PUT /v1/rules Replace selection rules when rule writes are enabled.
PUT /v1/overrides/{id} Pin or hide a normalized item.
POST /v1/mutate Apply source mutations when that source's writes are enabled.
GET /v1/permissions/{source} Check source write permission state.

Snapshot responses include:

{
  "items": [
    {
      "id": "calendar:event-example",
      "source": "calendar",
      "source_id": "event-example",
      "title": "Example meeting",
      "start": "2026-06-24T09:00:00Z",
      "end": "2026-06-24T09:30:00Z",
      "status": "open",
      "notes": "",
      "metadata": {
        "calendar": "Work"
      }
    }
  ],
  "all_items": [],
  "all_count": 1,
  "refreshed_at": "2026-06-23T18:00:00Z",
  "refresh_error": {},
  "rules": {
    "windows": {
      "calendar": 14,
      "things": 14,
      "obsidian": 30
    },
    "things_tags": ["Dashboard"],
    "things_areas": [],
    "things_projects": [],
    "calendars": [],
    "obsidian_paths": []
  },
  "overrides": {}
}

Selection Rules

SourceRelay selects items in three layers:

  1. Overrides: pinned items are always included; hidden items are excluded.
  2. Source rules: Things tags, Things areas, Things projects, calendars, and Obsidian paths.
  3. Date windows: upcoming Calendar events, dated Things tasks, and dated Obsidian items within each configured window.

Default rules:

{
  "windows": {
    "things": 14,
    "calendar": 14,
    "obsidian": 30
  },
  "things_tags": ["Dashboard"],
  "things_areas": [],
  "things_projects": [],
  "calendars": [],
  "obsidian_paths": []
}

Pinning And Hiding

Dashboards can pin or hide an item with:

curl \
  -X PUT \
  -H "Authorization: Bearer ${SOURCE_RELAY_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"pinned":true}' \
  http://127.0.0.1:8765/v1/overrides/calendar:event-example

Use {"hidden":true} to hide an item. Use false to clear a pin or hide state.

Overrides are stored separately from Calendar, Things 3, and Obsidian. They are dashboard preferences, not source edits.

Sync Model

SourceRelay is intentionally simple:

  1. The app reads enabled sources.
  2. The selection engine chooses dashboard-relevant items.
  3. The Bridge API serves the snapshot.
  4. Your dashboard pulls /v1/snapshot or triggers /v1/refresh.
  5. Optional pin and hide actions go back through /v1/overrides/{id}.
  6. Optional source writes go through /v1/mutate only if enabled in the app.

The default refresh interval is 300 seconds. A dashboard can also call POST /v1/refresh when the user clicks a sync button.

Diagnostics

The diagnostics UI is the fastest way to verify a setup:

  • Header shows live state and selected item count.
  • Upcoming lane shows countdown cards for selected time-based items.
  • Source summary shows Calendar, Things, and Obsidian totals.
  • Overrides show pinned and hidden items.
  • Obsidian panel shows selected Obsidian tasks and notes.
  • Raw table shows the normalized items your dashboard can consume.
  • Warning banner shows source errors without exposing credentials.

Open it from the app with Open Diagnostics.

Troubleshooting

The bridge says the address is already in use. Another process is using the API or diagnostics port. Choose another port in Bridge, click Save Settings, then restart the bridge.

The port changes after restart. Set API Port and Diagnostics Port manually in Bridge, click Save Settings, then restart. Saved settings live under ~/Library/Application Support/SourceRelay/.

The dashboard gets 401 Unauthorized. Copy a fresh API credential from the app and update your dashboard configuration.

Calendar is empty. Open Sources, grant Calendar access, then restart or refresh the bridge.

Things 3 is empty. Open Sources, allow Things automation, and make sure the tasks match your Things tags, areas, projects, or date window.

Obsidian is empty. Choose a vault in Sources and add one or more included Obsidian paths in your selection rules. SourceRelay only reads files inside the chosen vault.

macOS asks for Keychain access repeatedly. Choose Always Allow for the SourceRelay credential. If you are rebuilding frequently, macOS may treat each build as a new binary identity.

Development

Run tests:

swift test --package-path mac_app

Build the app bundle:

mac_app/scripts/package_app.sh

Run the publication scan before publishing:

scripts/publication_scan.sh

For release-grade scanning, install gitleaks and run:

scripts/publication_scan.sh --release

Optional signing:

SOURCE_RELAY_SIGN_IDENTITY="Developer ID Application: Example" \
mac_app/scripts/package_app.sh

Privacy Checklist Before Sharing A Build

  • Do not commit settings files, environment files, logs, local databases, or app support files.
  • Do not commit API credentials or screenshots containing private item titles.
  • Keep the API on 127.0.0.1 unless a trusted private network dashboard needs it.
  • Rotate the API credential if you accidentally paste it somewhere public.
  • Run the publication scan before pushing a public release.

License

MIT. See LICENSE.

About

A private macOS bridge that turns Calendar, Things 3, and Obsidian into one clean local API for personal dashboards.

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages