Skip to content

Latest commit

 

History

History
229 lines (180 loc) · 9.9 KB

File metadata and controls

229 lines (180 loc) · 9.9 KB

1Context Development And Release Notes

This document holds the maintainer details that used to make the README feel like an engineering manual. The README should stay product-first.

Start with README.md for the docs map. For release operations, use macOS Release Runbook as the current source of truth; this file keeps the supporting engineering details.

Local Files

1Context keeps user-owned content and app machinery separate:

~/1Context/
  user-wiki/        readable wiki source, talk, templates, assets, and export
  context-engine/   user-owned agent work, prompts, runs, ledgers, and manifests

~/Library/Application Support/1Context/
  app/runtime state, config, sockets, queues, local web mirrors, and derived indexes

~/Library/Logs/1Context/
  logs and debug/support information

~/Library/Caches/1Context/
  disposable cache, safe to delete

The production user-data contract lives in user-data-spec.md. The repo-local development mirror is described in ../runtime/README.md.

See ../PERMISSIONS.md for the ownership, consent, and privacy contract used by the runtime and installer.

Privacy

The public preview makes no product telemetry calls and does not upload project data. Update policy, appcast diagnostics, and CLI-readable update snapshots live in OneContextUpdate; the actual Sparkle framework driver lives in OneContextSparkleUpdate. Setup and runtime readiness do not carry update state.

Local Web

The release app bundles Caddy and serves the local wiki at the canonical local URL reported by:

1context wiki local-url

Product mode requires local wiki access setup. The app opens the setup window on launch, repair, and from Settings > Setup.... Setup registers the bundled ServiceManagement helper for 127.0.0.1:443 and trusts the local Caddy CA in the user's login keychain so browsers can open the canonical URL without a port. The CLI is intentionally not a setup or lifecycle control plane; setup stays in the app UI and redacted setup state is visible through 1context diagnose.

The menu bar owns Caddy lifetime. The daemon owns the local /api/wiki/* adapter and the wiki refresh entrypoint. Browser code should call relative /api/wiki/* routes so the same static site can run behind local Caddy today and cloud hosting later.

See local-web-contract.md for the local-first web contract.

See macos-app-architecture.md for the app-owned setup, permissions, update, and local-web source boundaries.

Test Commands

swift test --package-path macos
./scripts/test.sh

For updater work, keep tests on update policy, appcast configuration, the Sparkle controller, the menu update path, redacted diagnostics, and the release feed. Public update controls live in the app, not in the CLI.

Release Packaging

Local Apple Development signed packaging:

./scripts/release-train.sh build --channel dev

The dev channel builds a side-by-side app identity instead of another copy of the official app:

dist/1Context Dev.app
/Applications/1Context Dev.app
bundle id: com.haptica.1context.dev
user data: ~/1Context-Dev
app support: ~/Library/Application Support/1Context Dev
logs: ~/Library/Logs/1Context Dev
preferences: ~/Library/Preferences/com.haptica.1context.dev.plist
local wiki: http://localhost:39291/your-context

To install the dev app without colliding with the official release:

./scripts/release-train.sh build --channel dev
ditto --norsrc --noqtn "dist/1Context Dev.app" "/Applications/1Context Dev.app"
open -na "/Applications/1Context Dev.app"
"/Applications/1Context Dev.app/Contents/MacOS/1context-cli" diagnose

The official app remains /Applications/1Context.app with bundle id com.haptica.1context, ~/1Context, and the portless local HTTPS helper. The dev app uses an unprivileged HTTP localhost port by default, so it does not take over the official 443 helper or Sparkle feed.

The dev channel is fast local signing, not release signing: it uses the local Apple Development certificate when available and skips notarization. Keep this mode for normal iteration because macOS privacy grants are keyed to the app's designated signing requirement, not just the bundle id. Rebuilding the same bundle id with ad-hoc signing can make System Settings show a granted toggle while the running build still reports Screen Recording, Accessibility, or Input Monitoring as missing.

When the task is specifically to test the first-run permission flow, build a fresh dev identity on purpose. Keep the build time in a variable so the app name, bundle id, install path, diagnostics, and evidence files all line up:

BUILD_TIME="$(date +%Y%m%d-%H%M%S)"
/usr/bin/time -p env ONECONTEXT_PERMISSION_TEST_ID="$BUILD_TIME" \
  ./scripts/release-train.sh build --channel dev

APP_NAME="1Context Dev - $BUILD_TIME"
ditto --norsrc --noqtn "dist/$APP_NAME.app" "/Applications/$APP_NAME.app"
open -na "/Applications/$APP_NAME.app"
"/Applications/$APP_NAME.app/Contents/MacOS/1context-cli" diagnose

ONECONTEXT_APP="/Applications/$APP_NAME.app" \
ONECONTEXT_INCLUDE_BROWSER_EXTENSION=1 \
./scripts/test-installed-app-live-permission-capabilities.sh

That produces dist/1Context Dev - <suffix>.app with bundle id com.haptica.1context.dev.permission.<suffix> and a matching permission-test runtime identity. Its app support, logs, preferences, LaunchAgent labels, and localhost ports are also suffix-scoped so it can run beside the stable dev app without reusing its proof records or instance lock. Install that app when you want a clean TCC identity and fresh prompts. Do not use the permission-test identity to judge whether normal dev rebuilds preserve existing permissions. scripts/test-installed-app-live-permission-capabilities.sh is intentionally limited to this timestamped dev identity and requires ONECONTEXT_APP; it does not probe stable dev or production apps. When reporting a timestamped build, include the BUILD_TIME, the installed app path, the real/user/sys timing from /usr/bin/time -p, and the live permission probe evidence path if permissions were part of the task.

The setup page stores signed-subject proof records for permission lanes that can otherwise inherit misleading state across dev builds. Proof records include the bundle identifier, app version, and designated code requirement digest; a matching bundle id alone is not enough. Input Monitoring, Browser Extension Permissions, Automation, Screen & System Audio Recording, and Microphone should be tested from the signed app UI, not from 1context-cli in Terminal. A CLI or Terminal-launched helper can exercise the wrong TCC subject and is useful for diagnostics only after the app has written its own proof record. Every app build also writes permission identity evidence under dist/permission-build-evidence/ with the app path, designated requirement, entitlements, and usage strings.

Maintainer release packaging uses Developer ID signing, notarization, and the production Sparkle feed configuration:

./scripts/release-train.sh build --channel official

The release train reads release/release.toml, auto-detects the Developer ID Application identity, reads the Sparkle public EdDSA key from the release keychain account or ONECONTEXT_SPARKLE_PUBLIC_ED_KEY, signs and notarizes the app and DMG, then generates dist/sparkle-updates/appcast.xml. For the protected self-hosted release workflow, scripts/prepare-macos-release-keychain.sh unlocks the dedicated release keychain and scripts/check-macos-release-credentials.sh preflights Developer ID signing, Sparkle signing, and the notary profile before any artifact is built. The GitHub Release workflow defaults to validation-only mode so it does not queue the protected self-hosted Mac by accident. Dispatch it with run_signed_publish=true to build, sign, notarize, publish, and audit public assets. Keep run_self_hosted_proof=false unless you also want the real-Mac Sparkle proof and bless pass for that release.

Release packaging validates that archives do not contain local owner/group metadata, AppleDouble files, Homebrew paths, local build paths, SwiftPM resource-bundle fallback paths, stale wiki manifests, or generated markdown source files in the bundled user-wiki surface.

Production packaging signs and notarizes both layers:

  1. dist/1Context.app is Developer ID signed, submitted as a ZIP, stapled, and assessed with Gatekeeper.
  2. dist/1Context-<version>-macos-arm64.dmg is signed, submitted, stapled, and assessed with Gatekeeper.

scripts/release-train.sh build --channel dev is the local Apple Development signed package path. It is not a release command. Prototype, private, and official channels must bundle their release-owned runtime inputs and must not install or resolve Homebrew packages while creating the shipped .app or DMG.

The self-hosted Mac update proof is required for official releases that list it in release/release.toml. Private and official updater hops should be proved by the factory instead of by hand-filled workflow inputs.

When the release owner decides the Mac proof is warranted, use scripts/release-train.sh prove so release/release.toml owns the update class, old-version baseline, appcast URL, and protected workflow dispatch. The version-N app installed by the proof must already have SUFeedURL set to the manifest appcast URL; rebuild the release artifact from the manifest instead of passing a one-off staging feed through workflow inputs.

./scripts/release-train.sh prove

To notarize a built release artifact directly, first configure a notarytool keychain profile. Direct DMG notarization expects the DMG to already be signed:

NOTARYTOOL_PROFILE=1context-notary ./release/tools/notarize-macos-artifact.sh dist/1Context.app
NOTARYTOOL_PROFILE=1context-notary ./release/tools/notarize-macos-artifact.sh dist/1Context-<version>-macos-arm64.dmg