Skip to content

CloudLens demo app: menu bar cloud sentinel (milestone 2)#3

Closed
jeffreyaven wants to merge 3 commits into
feature/embedded-swift-mcpfrom
feature/cloudlens-demo-app
Closed

CloudLens demo app: menu bar cloud sentinel (milestone 2)#3
jeffreyaven wants to merge 3 commits into
feature/embedded-swift-mcpfrom
feature/cloudlens-demo-app

Conversation

@jeffreyaven

Copy link
Copy Markdown
Member

Milestone 2: the CloudLens menu bar cloud sentinel demo app.

Based on the package branch (PR #1) so this PR shows only the CloudLens delta. Merge #1 first, then this retargets to main.

Structure

Two SwiftPM targets so the logic is CI-testable without a GUI:

CloudLensCore (library, no SwiftUI):

  • Domain model (Finding/Severity/PulseKind/PulseResult) carrying the SQL behind each finding through to notifications.
  • FindingDiff - pure menu-bar-state derivation + new-since-last-run diff.
  • Pulse protocol + RowParser and three pulses: PosturePulse (github null_auth, the zero-cred demo pulse), SpendPulse/ExposurePulse (AWS, degrade to "not configured" without creds rather than a false all-calm).
  • SentinelModel - @MainActor orchestrator: starts the embedded server, runs the suite, derives state, diffs, fires the new-findings hook.
  • AnthropicAgent - URLSession Messages API client (no official Swift SDK), x-api-key + anthropic-version, claude-opus-4-8; key from Keychain, never bundled.
  • Keychain - generic-password secret store.

CloudLens (executable, SwiftUI):

  • MenuBarExtra app; icon reflects calm/attention/unknown; popover shows the three pulses with each finding's SQL (selectable). AppDelegate runs an initial check at launch then on a 15-min schedule.
  • Notifications - one native notification per new attention finding, body includes the SQL behind it.

Tests

CloudLensCoreTests (offline): finding diff/state, row parsing, each pulse's finding generation + severity thresholds, agent prompt building + response extraction. CI builds the CloudLens product explicitly and runs the new test target.

Notes

  • The signed/notarised .app that bundles the binary is the documented packaging step (docs/bundling-and-notarisation.md), not a CI artifact.
  • AWS/Azure/GCP pulses run their SQL but need Keychain creds; the github posture pulse demos with zero creds and is what CI exercises.

Generated with Claude Code.

jeffreyaven and others added 3 commits June 13, 2026 18:03
CloudLens embeds the StackQL MCP server and runs a small read_only pulse
suite, surfacing state in the macOS menu bar with native notifications.

Structure (two SwiftPM targets so the logic is CI-testable without a GUI):

CloudLensCore (library, no SwiftUI):
- Finding/Severity/PulseKind/PulseResult domain model with the SQL behind
  each finding carried through to notifications.
- FindingDiff: pure menu-bar-state derivation and new-since-last-run diff.
- Pulse protocol + RowParser (parses StackQL JSON-array tool output) and
  three pulses: PosturePulse (github null_auth, the zero-cred demo pulse),
  SpendPulse and ExposurePulse (AWS, degrade to "not configured" without
  creds rather than a false all-calm).
- SentinelModel: @mainactor orchestrator - starts the embedded server, runs
  the suite, derives state, diffs, fires the new-findings hook.
- AnthropicAgent: URLSession Messages API client (no official Swift SDK),
  x-api-key + anthropic-version headers, claude-opus-4-8, key never bundled.
- Keychain: generic-password store for the Anthropic key.

CloudLens (executable, SwiftUI):
- MenuBarExtra app; icon reflects calm/attention/unknown; popover shows the
  three pulses with each finding's SQL (selectable). AppDelegate runs an
  initial check at launch then on a 15-minute schedule.
- Notifications: one native notification per new attention finding, body
  includes the SQL behind it.

Tests (CloudLensCoreTests, offline): finding diff/state, row parsing, each
pulse's finding generation and severity thresholds, agent prompt building and
response extraction. CI builds the CloudLens product explicitly and runs the
new test target (swift build/test already cover both).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Long-lived feature branches may stack on each other (CloudLens is based on
the package branch, not main), so a PR whose base is another feature branch
never matched 'pull_request: branches: [main]' and got no CI. Run on every
PR and on pushes to main and feature/** so stacked branches are validated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A [String: String] literal of runtime variables does not implicitly convert
to [String: Value] (Value's ExpressibleByStringLiteral only applies to string
literals). Add a call(_:stringArgs:) overload that maps via
Value(stringLiteral:) and use it from the pulses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant