diff --git a/BRANDING.md b/BRANDING.md index 1a3fcd3f0..574381d65 100644 --- a/BRANDING.md +++ b/BRANDING.md @@ -13,10 +13,10 @@ | **Stage Label** | Dev (development only) | | **Display Name** | OK Code | | **Version** | 0.0.1 | -| **Tagline** | `[TBD]` | -| **One-liner Description** | `[TBD]` | +| **Tagline** | A Minimal Web GUI for Coding Agents | +| **One-liner Description** | Chat with Codex and Claude in a modern web UI. Git worktree isolation, diff review, integrated terminal, and more. | | **Parent Organization** | OpenKnots | -| **Website URL** | `[TBD]` | +| **Website URL** | `[TBD]` | | **Repository** | `OpenKnots/okcode` | ### Brand Voice & Tone @@ -27,8 +27,8 @@ | **Tone** | Confident but not arrogant; technical but accessible | | **Copy Style** | Action-oriented imperatives ("New Thread", "Terminal", "Settings"); no unnecessary filler words | | **Audience** | Software engineers and technical users | -| **Emoji Usage** | `[TBD — currently none in the UI]` | -| **Error/Empty States Voice** | `[TBD]` | +| **Emoji Usage** | None in UI copy; reserved for user-generated content only | +| **Error/Empty States Voice** | Concise and helpful; state what happened and what to do next, no blame or humor | --- @@ -256,7 +256,7 @@ A subtle **fractal noise SVG overlay** is applied to `body::after` at **3.5% opa | Disabled opacity | `opacity-64` | | Disabled interaction | `pointer-events: none` | | Placeholder text | `muted-foreground/72` (72% opacity) | -| Contrast standard | `[TBD — WCAG level target]` | +| Contrast standard | WCAG 2.1 AA minimum | --- @@ -321,7 +321,7 @@ The app includes bespoke SVG icons for: | Property | Value | | -------------------------------- | ------- | -| `prefers-reduced-motion` support | `[TBD]` | +| `prefers-reduced-motion` support | Respect; disable non-essential animations when set | | Global animation toggle | `[TBD]` | --- @@ -385,19 +385,19 @@ Built with: The following need to be provided/decided: -- [ ] **Tagline** — short memorable phrase -- [ ] **One-liner description** — for app stores, meta tags, social cards +- [x] **Tagline** — "A Minimal Web GUI for Coding Agents" +- [x] **One-liner description** — see Brand Identity table above +- [x] **WCAG contrast target** — AA minimum +- [x] **Reduced motion support** — respect `prefers-reduced-motion` +- [x] **Emoji policy** — none in UI copy +- [x] **Error/empty state voice** — concise and helpful - [ ] **Logo mark description** — what does the mark depict? - [ ] **Logo usage guidelines** — minimum size, clear space, do's and don'ts - [ ] **Heading type scale** — H1–H6 sizes and weights -- [ ] **WCAG contrast target** — AA or AAA? -- [ ] **Reduced motion support** — respect `prefers-reduced-motion`? - [ ] **Website URL** - [ ] **Social media handles / links** - [ ] **App store descriptions** - [ ] **Open Graph / social card image** - [ ] **Brand color as hex** — the primary `oklch(0.488 0.217 264)` converts to approximately **#2b4acb** (a deep blue-violet); confirm this is the intended brand hex - [ ] **Secondary brand color** — is there a distinct secondary brand color beyond the neutral system? -- [ ] **Emoji policy** — use in UI copy, notifications, etc.? -- [ ] **Error/empty state voice** — tone for error messages, empty states, onboarding - [ ] **Icon stroke width** — confirm Lucide default (2) or custom diff --git a/LICENSE b/LICENSE index e3266a808..c11b137eb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 OpenKnot +Copyright (c) 2026 OpenKnots Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/apps/desktop/scripts/electron-launcher.mjs b/apps/desktop/scripts/electron-launcher.mjs index 5e48b2866..9cd91ddd5 100644 --- a/apps/desktop/scripts/electron-launcher.mjs +++ b/apps/desktop/scripts/electron-launcher.mjs @@ -17,8 +17,10 @@ import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL); -const APP_DISPLAY_NAME = isDevelopment ? "OK Code (Dev)" : "OK Code"; -const APP_BUNDLE_ID = "com.okcode.okcode"; +// Keep in sync with APP_BASE_NAME from @okcode/shared/brand +const APP_BASE_NAME = "OK Code"; +const APP_DISPLAY_NAME = isDevelopment ? `${APP_BASE_NAME} (Dev)` : APP_BASE_NAME; +const APP_BUNDLE_ID = "com.openknots.okcode"; const LAUNCHER_VERSION = 1; const __dirname = dirname(fileURLToPath(import.meta.url)); diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 86d96efaa..18dfbeaa3 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -26,6 +26,7 @@ import type { PreviewTabsState, } from "@okcode/contracts"; import { autoUpdater } from "electron-updater"; +import { APP_BASE_NAME } from "@okcode/shared/brand"; import type { ContextMenuItem } from "@okcode/contracts"; import { NetService } from "@okcode/shared/Net"; @@ -79,8 +80,8 @@ const STATE_DIR = Path.join(BASE_DIR, "userdata"); const DESKTOP_SCHEME = "okcode"; const ROOT_DIR = Path.resolve(__dirname, "../../.."); const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL); -const APP_DISPLAY_NAME = isDevelopment ? "OK Code (Dev)" : "OK Code"; -const APP_USER_MODEL_ID = "com.okcode.okcode"; +const APP_DISPLAY_NAME = isDevelopment ? `${APP_BASE_NAME} (Dev)` : APP_BASE_NAME; +const APP_USER_MODEL_ID = "com.openknots.okcode"; const USER_DATA_DIR_NAME = isDevelopment ? "okcode-dev" : "okcode"; const LEGACY_USER_DATA_DIR_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; const COMMIT_HASH_PATTERN = /^[0-9a-f]{7,40}$/i; diff --git a/apps/marketing/components/workflows-section.tsx b/apps/marketing/components/workflows-section.tsx index 1f29cbafc..d3d7dc11d 100644 --- a/apps/marketing/components/workflows-section.tsx +++ b/apps/marketing/components/workflows-section.tsx @@ -203,7 +203,7 @@ function ApiMockup() { return (
- OK CODE API + OK Code API
); diff --git a/apps/server/src/checkpointing/Layers/CheckpointStore.ts b/apps/server/src/checkpointing/Layers/CheckpointStore.ts index 103043b88..7e32ba411 100644 --- a/apps/server/src/checkpointing/Layers/CheckpointStore.ts +++ b/apps/server/src/checkpointing/Layers/CheckpointStore.ts @@ -18,6 +18,7 @@ import { GitCommandError } from "../../git/Errors.ts"; import { GitCore } from "../../git/Services/GitCore.ts"; import { CheckpointStore, type CheckpointStoreShape } from "../Services/CheckpointStore.ts"; import { CheckpointRef } from "@okcode/contracts"; +import { GIT_IDENTITY_NAME } from "@okcode/shared/brand"; const makeCheckpointStore = Effect.gen(function* () { const fs = yield* FileSystem.FileSystem; @@ -98,9 +99,9 @@ const makeCheckpointStore = Effect.gen(function* () { const commitEnv: NodeJS.ProcessEnv = { ...process.env, GIT_INDEX_FILE: tempIndexPath, - GIT_AUTHOR_NAME: "OK Code", + GIT_AUTHOR_NAME: GIT_IDENTITY_NAME, GIT_AUTHOR_EMAIL: "okcode@users.noreply.github.com", - GIT_COMMITTER_NAME: "OK Code", + GIT_COMMITTER_NAME: GIT_IDENTITY_NAME, GIT_COMMITTER_EMAIL: "okcode@users.noreply.github.com", }; diff --git a/apps/server/src/provider/codexCliVersion.ts b/apps/server/src/provider/codexCliVersion.ts index a24d66d54..893ba95b6 100644 --- a/apps/server/src/provider/codexCliVersion.ts +++ b/apps/server/src/provider/codexCliVersion.ts @@ -1,3 +1,5 @@ +import { APP_BASE_NAME } from "@okcode/shared/brand"; + const CODEX_VERSION_PATTERN = /\bv?(\d+\.\d+(?:\.\d+)?(?:-[0-9A-Za-z.-]+)?)\b/; export const MINIMUM_CODEX_CLI_VERSION = "0.37.0"; @@ -137,5 +139,5 @@ export function isCodexCliVersionSupported(version: string): boolean { export function formatCodexCliUpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; - return `Codex CLI ${versionLabel} is too old for OK Code. Upgrade to v${MINIMUM_CODEX_CLI_VERSION} or newer and restart OK Code.`; + return `Codex CLI ${versionLabel} is too old for ${APP_BASE_NAME}. Upgrade to v${MINIMUM_CODEX_CLI_VERSION} or newer and restart ${APP_BASE_NAME}.`; } diff --git a/apps/web/src/branding.ts b/apps/web/src/branding.ts index 28d72b856..66526c890 100644 --- a/apps/web/src/branding.ts +++ b/apps/web/src/branding.ts @@ -1,4 +1,5 @@ -export const APP_BASE_NAME = "OK Code"; +export { APP_BASE_NAME } from "@okcode/shared/brand"; + export const APP_STAGE_LABEL = import.meta.env.DEV ? "Dev" : ""; export const APP_DISPLAY_NAME = APP_STAGE_LABEL ? `${APP_BASE_NAME} (${APP_STAGE_LABEL})` diff --git a/apps/web/src/components/ChatHomeEmptyState.tsx b/apps/web/src/components/ChatHomeEmptyState.tsx index a0fd6bc25..61a8c385e 100644 --- a/apps/web/src/components/ChatHomeEmptyState.tsx +++ b/apps/web/src/components/ChatHomeEmptyState.tsx @@ -15,7 +15,7 @@ import { import { useCallback, useMemo, useState } from "react"; import { useAppSettings } from "../appSettings"; -import { APP_DISPLAY_NAME } from "../branding"; +import { APP_BASE_NAME, APP_DISPLAY_NAME } from "../branding"; import { isElectron } from "../env"; import { useHandleNewThread } from "../hooks/useHandleNewThread"; import { serverConfigQueryOptions } from "../lib/serverReactQuery"; @@ -363,7 +363,7 @@ export function ChatHomeEmptyState() { Launch a premium coding workspace with reliable agent sessions built in.

- OK Code keeps threads tied to real repositories, preserves provider state, + {APP_BASE_NAME} keeps threads tied to real repositories, preserves provider state, and gives your desktop a calmer control surface for deep, multi-session work.

diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 272a65aab..b159ac84d 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -50,7 +50,7 @@ import { useAppSettings, } from "../appSettings"; import { isElectron } from "../env"; -import { APP_VERSION } from "../branding"; +import { APP_BASE_NAME, APP_VERSION } from "../branding"; import { cn, isLinuxPlatform, isMacPlatform, newCommandId, newProjectId } from "../lib/utils"; import { useStore } from "../store"; import { shortcutLabelForCommand } from "../keybindings"; @@ -1805,8 +1805,8 @@ export default function Sidebar() { render={
- - OK Code + + {APP_BASE_NAME}
} @@ -1860,7 +1860,7 @@ export default function Sidebar() { onClick={() => { toastManager.add({ type: "info", - title: `OK Code ${serverUpdateInfo.latestVersion} available`, + title: `${APP_BASE_NAME} ${serverUpdateInfo.latestVersion} available`, description: `Update with: npm install -g okcodes@latest`, }); }} diff --git a/packages/shared/package.json b/packages/shared/package.json index 2f0b4010f..01f71adca 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -47,6 +47,10 @@ "./skillCatalog": { "types": "./src/skillCatalog.ts", "import": "./src/skillCatalog.ts" + }, + "./brand": { + "types": "./src/brand.ts", + "import": "./src/brand.ts" } }, "scripts": { diff --git a/packages/shared/src/brand.ts b/packages/shared/src/brand.ts new file mode 100644 index 000000000..bb9590c0d --- /dev/null +++ b/packages/shared/src/brand.ts @@ -0,0 +1,13 @@ +/** + * Canonical brand constants for the OK Code product. + * + * Import from `@okcode/shared/brand` in any workspace package. + * The web app's `branding.ts` re-exports these with Vite-specific additions + * (stage labels, build-time version injection). + */ + +/** Base product name — use for display text that should not include a stage label. */ +export const APP_BASE_NAME = "OK Code"; + +/** Git committer identity used by OK Code's internal operations (checkpoints, etc.). */ +export const GIT_IDENTITY_NAME = APP_BASE_NAME; diff --git a/scripts/build-desktop-artifact.ts b/scripts/build-desktop-artifact.ts index 6c6dad829..33e5519f1 100644 --- a/scripts/build-desktop-artifact.ts +++ b/scripts/build-desktop-artifact.ts @@ -8,6 +8,7 @@ import rootPackageJson from "../package.json" with { type: "json" }; import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" }; import serverPackageJson from "../apps/server/package.json" with { type: "json" }; +import { APP_BASE_NAME } from "@okcode/shared/brand"; import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts"; import { resolveCatalogDependencies } from "./lib/resolve-catalog.ts"; @@ -519,7 +520,7 @@ const createBuildConfig = Effect.fn("createBuildConfig")(function* ( macEntitlementsPlistAbsolutePath: string | undefined, ) { const buildConfig: Record = { - appId: "com.okcode.okcode", + appId: "com.openknots.okcode", productName, artifactName: "OK-Code-${version}-${arch}.${ext}", directories: { @@ -736,7 +737,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( build: yield* createBuildConfig( options.platform, options.target, - desktopPackageJson.productName ?? "OK Code", + desktopPackageJson.productName ?? APP_BASE_NAME, options.signed, options.signed && options.platform === "mac" ? macEntitlementsPlistAbsolutePath : undefined, ), diff --git a/scripts/generate-brand-assets.py b/scripts/generate-brand-assets.py index de1d46597..ed9b84f01 100644 --- a/scripts/generate-brand-assets.py +++ b/scripts/generate-brand-assets.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 """Regenerate favicons and desktop icon PNGs/ICOs from assets/source/okcode-mark-512.png. -Windows `.ico` files use `assets/source/openknot-mark-512.png` when present (OpenKnots org -mark); otherwise they fall back to the OK Code mark. +All platforms (macOS, Windows, Linux, iOS, web) use the same OK Code mark as their source. Requires Pillow (`python3 -m pip install pillow` if missing). Run from repository root: python3 scripts/generate-brand-assets.py @@ -22,7 +21,6 @@ ROOT = Path(__file__).resolve().parents[1] SRC = ROOT / "assets/source/okcode-mark-512.png" -OPENKNOT_MARK_SRC = ROOT / "assets/source/openknot-mark-512.png" ICO_SIZES_WEB = (16, 32, 48) ICO_SIZES_DESKTOP = (16, 32, 48, 64, 128, 256) @@ -99,11 +97,6 @@ def main() -> None: img = Image.open(SRC).convert("RGBA") - if OPENKNOT_MARK_SRC.exists(): - windows_icon_source = Image.open(OPENKNOT_MARK_SRC).convert("RGBA") - else: - windows_icon_source = img - # Master 1024 for desktop / marketing hero mark_1024 = resize(img, 1024) prod_dir = ROOT / "assets/prod" @@ -133,8 +126,8 @@ def main() -> None: save_ico(prod_dir / "okcode-web-favicon.ico", img, ICO_SIZES_WEB) save_ico(dev_dir / "okcode-dev-web-favicon.ico", img, ICO_SIZES_WEB) - save_ico(prod_dir / "okcode-windows.ico", windows_icon_source, ICO_SIZES_DESKTOP) - save_ico(dev_dir / "okcode-dev-windows.ico", windows_icon_source, ICO_SIZES_DESKTOP) + save_ico(prod_dir / "okcode-windows.ico", img, ICO_SIZES_DESKTOP) + save_ico(dev_dir / "okcode-dev-windows.ico", img, ICO_SIZES_DESKTOP) # Marketing site: large nav icon + same favicons as prod web mkt = ROOT / "apps/marketing/public"