Local development
AvailableUse the repository root for desktop app development and app/ for website
(and documentation) development.
Clerk development environments
Reuse the existing production Clerk instance and users; do not replace or migrate production identities. Keep a separate Clerk development instance. Local website runs use the development instance's publishable key; production DNS, OAuth applications, redirects, and webhooks belong only to the existing production instance.
The website reads its browser publishable key and server-only credentials from
its environment files under app/. Because the website also renders the
documentation you are reading, there is no separate documentation process,
key, or origin to keep in sync — the same dev server and the same publishable
key cover both.
Do not add Clerk server secrets, webhook signing secrets, session tokens, or
desktop OAuth credentials anywhere public content is generated from.
Development startup accepts only a syntactically valid Clerk publishable key
beginning with pk_test_ or pk_live_. A production build accepts only the
valid pk_live_ key whose Frontend API is exactly clerk.wrengle.com.
Railway's deployed production build requires that exact key. A malformed or
whitespace-padded value aborts before any credential can be serialized into
the public build.
The website serves both the marketing pages and the documentation from a single origin, so there is no separate documentation origin to configure.
All local surfaces
bun install
bun run dev:allThis starts the desktop app and the website — which also serves this
documentation — at http://localhost:3000. Press Ctrl-C in that terminal to
stop both.
For native account testing, create the public, PKCE-required desktop OAuth
Application in that same development instance. Root
WRENGLE_CLERK_ISSUER_URL must match the instance encoded in app's
VITE_CLERK_PUBLISHABLE_KEY; root WRENGLE_CLERK_DESKTOP_CLIENT_ID must equal
app's CLERK_DESKTOP_OAUTH_CLIENT_ID; and root
WRENGLE_ACCOUNT_API_URL must be exactly http://localhost:3000.
Copy that opaque Client ID from the OAuth Application's Application
credentials section. Current Clerk Client IDs are 16 alphanumeric characters
with no prefix; do not use a key, secret, token, or current oa_.../legacy
oauthapp_... application resource ID.
dev:all validates those public values before launch without forwarding server
secrets. Debug and release builds use separate stable OS-keychain account slots.
The desktop app launched through bun run tauri dev uses an amber development icon
so it is visually distinct from production builds in the Dock or taskbar. Release
builds keep the production Wrengle icon.
Internal Jira OAuth broker
The accounts app contains a dormant Jira Cloud OAuth exchange foundation. The desktop has optional account identity, but it has no Jira device-enrollment bridge, broker call site, or executable Jira workflow target. Every Jira broker route returns the same non-cacheable 404 in production and by default in development. To test only this internal foundation, opt in explicitly:
JIRA_OAUTH_BROKER_ENABLED=1
ATLASSIAN_OAUTH_CLIENT_ID=...
ATLASSIAN_OAUTH_CLIENT_SECRET=...
ATLASSIAN_OAUTH_CALLBACK_URL=https://your-dev-host/api/workflows/jira/oauth/callback
JIRA_OAUTH_DESKTOP_REDIRECT_URI=wrengle://oauth/jira
JIRA_OAUTH_BROKER_ENCRYPTION_KEY=... # base64-encoded 32-byte keyThe flag works only with NODE_ENV=development; production ignores it even if
it is accidentally configured. Run the Drizzle migration before testing. The
Atlassian console callback must exactly match ATLASSIAN_OAUTH_CALLBACK_URL.
Broker logs and tests must never print codes, handoffs, access tokens, refresh
tokens, or decrypted bundles. This developer opt-in is not a release smoke gate
and does not make Jira a shipped connection.
macOS Keychain prompts
Startup uses a non-secret catalog to enumerate every currently configured,
allowlisted app-owned secure item, then reads those items one at a time before
mounting the workspace. Provider and speech keys, connected-service OAuth
tokens, the current build's account bundle, configured-action and current-plugin
secrets, and required workflow secure state can each trigger an item-specific
macOS dialog for com.wrengle.app. Startup does not contact a provider, refresh
OAuth, verify an account, run an action, or grant a capability while doing this.
The requested password is the current Mac login password. Allow approves that item access once and is sufficient for the current session because ordinary feature paths use the sealed native cache. Always Allow remembers access for the current app identity. Deny puts only dependent capabilities in Limited mode. Opening Settings or using a feature cannot fall through to a new Keychain dialog.
The tauri dev app is ad-hoc signed, so a rebuild can change its code identity and
cause macOS to prompt again even after Always Allow. Do not rewrite Wrengle
keychain items with an allow-all access list: that would let unrelated local
processes read the credentials. Use separate development/test provider keys and
approve access only for the current app build.
If you previously ran the removed just dev-keychain-trust helper, removing the
helper does not repair the permissive access lists it wrote. Quit Wrengle, open
Keychain Access, select the login keychain, search for com.wrengle.app, and
delete only the Wrengle development credential items you intend to replace. Then
relaunch Wrengle and add replacement development keys or reconnect the affected
OAuth integration through the app so macOS creates new restricted items. Rotate
old development keys if other local processes could have read them. This recovery
intentionally uses no terminal command that reads or prints secret values.
When testing provider keys after startup, an explicit Save key, Replace, or Remove action made while Wrengle is focused may show the item-specific macOS dialog. This is expected when a development rebuild has a different ad-hoc identity; approve the change only for the Wrengle build you are running. Canceling or denying it fails closed and revokes the affected session authority. Background rotations, automatic cleanup, and ordinary feature use keep authentication UI disabled. A restart retries only entries still authorized by non-secret startup metadata; broker failed-mutation tombstones deliberately cannot rediscover an old physical value. The native cache is zeroizing process memory and is never exposed through generated bindings, logs, telemetry, or frontend storage.
Build and tests
just ci is the canonical local approximation of CI. It runs logic tests, lints, the
frontend build, unit tests, version checks, and bindings drift.
just ciBefore release work, also run:
just release-preflightWebsite and documentation
The documentation you are reading lives as content under app/content/docs,
rendered by the same website that serves the marketing pages. There is no
separate documentation project, dependency install, or build.
bun install --cwd app --frozen-lockfile
bun run --cwd app typecheck
bun run --cwd app test
bun run --cwd app devTypechecking and tests need no account or database environment. The production
build does: prerendering renders real routes through a preview server and fails
with DATABASE_URL is required before writing a page when deploy-shaped inputs
are absent. Run the repository-root just ci command for the canonical
build validation; it supplies the current throwaway values defined by the root
justfile's app_ci_env. If you need only the app build, use those exact
current values with bun run --cwd app build rather than treating a plain,
environment-free build failure as a product failure.
Run the website's tests once without a publishable key to verify the public fallback, then repeat a browser smoke test with the development publishable key to verify sign-in return URLs, Dashboard/Manage account/Sign out actions, continued access when Clerk requests are blocked, and that signing in on a marketing page leaves you signed in on a documentation page.
Internal development routes
The desktop app may include /dev/* routes during development. /dev/job-demo
is a non-blocking job UI demo for validating local job/status behavior; it is an
internal development surface, not a public product workflow.