diff --git a/README.md b/README.md
index c7ab1a460a22f..886f841e7cad1 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,16 @@
-# Ada
-
-**Agentic Desktop Application. Engineering is better with Agents.**
-
-Ada lets you direct the coding agents on your machine (Claude Code, Codex, Cursor, Grok Build,
+
);
}
diff --git a/apps/web/src/components/settings/BranchNamingSettings.tsx b/apps/web/src/components/settings/BranchNamingSettings.tsx
index d5365e8c912b3..ba1ef40b29550 100644
--- a/apps/web/src/components/settings/BranchNamingSettings.tsx
+++ b/apps/web/src/components/settings/BranchNamingSettings.tsx
@@ -81,7 +81,7 @@ export function BranchNamingSettings() {
serverScoped
settingKeys={["branchNamePrefix"]}
title="Branch prefix"
- description="For example, t3 or t3/ produces t3/add-search. Leave empty for no prefix."
+ description="For example, ada or ada/ produces ada/add-search. Leave empty for no prefix."
resetAction={
prefixMixed ||
settings.branchNamePrefix !== DEFAULT_SERVER_SETTINGS.branchNamePrefix ? (
diff --git a/apps/web/src/components/settings/LabsSettingsPanel.tsx b/apps/web/src/components/settings/LabsSettingsPanel.tsx
index 948dec2d7cdd7..b4827188589b1 100644
--- a/apps/web/src/components/settings/LabsSettingsPanel.tsx
+++ b/apps/web/src/components/settings/LabsSettingsPanel.tsx
@@ -150,7 +150,7 @@ function FastWorktreeCheckoutRow() {
serverScoped
{...searchableSetting("worktree-fast-checkout")}
settingKeys={["fastWorktreeCheckout"]}
- description="On a Mac, clone new worktrees from a checkout cached in the T3 home folder instead of writing every file. Uses Git’s normal checkout when it can’t. Turning it off deletes the cache."
+ description="On a Mac, clone new worktrees from a checkout cached in the Ada home folder instead of writing every file. Uses Git’s normal checkout when it can’t. Turning it off deletes the cache."
control={
setPairingCode(event.target.value)}
placeholder={
machine === null
- ? "From that environment's Connections, or t3 pair there"
+ ? "From that environment's Connections, or ada pair there"
: "Paste the code"
}
disabled={busy}
diff --git a/apps/web/src/components/settings/SettingsPanels.tsx b/apps/web/src/components/settings/SettingsPanels.tsx
index 574e7f2728e56..2304bd4dc7788 100644
--- a/apps/web/src/components/settings/SettingsPanels.tsx
+++ b/apps/web/src/components/settings/SettingsPanels.tsx
@@ -1,6 +1,5 @@
import { useAtomValue } from "@effect/atom-react";
import { NotificationSettings } from "./NotificationSettings";
-import { PRIVACY_POLICY_URL } from "../../legalLinks";
import { CheckIcon } from "lucide-react";
import { Link, useNavigate } from "@tanstack/react-router";
import { useRef, useState } from "react";
@@ -31,7 +30,7 @@ import {
ScreenReaderAnnouncements,
ToolCallVisibility,
} from "@t3tools/contracts/settings";
-import { desktopUpdateChannelOf } from "@t3tools/shared/cliRelease";
+import { desktopUpdateChannelOf, LICENSE_URL } from "@t3tools/shared/cliRelease";
import { createModelSelection } from "@t3tools/shared/model";
import { resolvePastedPath } from "@t3tools/shared/path";
import * as Equal from "effect/Equal";
@@ -75,7 +74,7 @@ import { ProjectDefaultsSettings } from "./ProjectDefaultsSettings";
import { ThreadTitleInstructionsSettings } from "./ThreadTitleInstructionsSettings";
import { SnoozePresetsRow } from "./SnoozePresetsSettings";
import { useDesktopUpdateState } from "../../state/desktopUpdate";
-import { managedTelemetryOffMessage, usePrimaryManagedPolicy } from "../../state/managedPolicy";
+import { usageDataNotice, usePrimaryManagedPolicy } from "../../state/managedPolicy";
import {
getCustomModelOptionsByInstance,
resolveAppModelSelectionState,
@@ -2344,7 +2343,6 @@ export function AboutSettingsPanel() {
const primaryPolicy = usePrimaryManagedPolicy();
// The Welcome page sets up this computer, so it needs one.
const primaryEnvironmentId = usePrimaryEnvironmentId();
- const telemetryOff = managedTelemetryOffMessage(primaryPolicy);
return (
@@ -2398,19 +2396,19 @@ export function AboutSettingsPanel() {
+ }
+ render={}
size="sm"
variant="outline"
>
- View policy
+ View license
}
/>
diff --git a/apps/web/src/components/settings/StorageSettings.tsx b/apps/web/src/components/settings/StorageSettings.tsx
index 312fdde385467..666fb1a3fd40b 100644
--- a/apps/web/src/components/settings/StorageSettings.tsx
+++ b/apps/web/src/components/settings/StorageSettings.tsx
@@ -69,7 +69,7 @@ export function WorktreesDirectoryRow() {
writeTextToClipboard(TRIAGE_CLI_COMMAND, "command").catch(() =>
@@ -31,7 +31,7 @@ const copyTriageCliCommand = () =>
export const isTriagePrompt = (prompt: string) => prompt.includes(`[${TRIAGE_PROMPT_FILE_NAME}](`);
/**
- * In-app `t3 triage`: the server writes the session files and starts cloning
+ * In-app `ada triage`: the server writes the session files and starts cloning
* the matching source, then a No project draft opens with the playbook linked.
* The draft hero explains the rest; the user picks a provider and describes
* the problem.
diff --git a/apps/web/src/legalLinks.ts b/apps/web/src/legalLinks.ts
deleted file mode 100644
index 2c42b814355f0..0000000000000
--- a/apps/web/src/legalLinks.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const PRIVACY_POLICY_URL = "https://t3.codes/privacy-policy";
diff --git a/apps/web/src/lib/bootError.test.ts b/apps/web/src/lib/bootError.test.ts
index e903c13b0b287..4083990a80064 100644
--- a/apps/web/src/lib/bootError.test.ts
+++ b/apps/web/src/lib/bootError.test.ts
@@ -43,18 +43,18 @@ describe("resolveTriageCommand", () => {
it("falls back to npx without a usable desktop launcher", async () => {
using _warn = vi.spyOn(console, "warn").mockImplementation(() => {});
- await expect(resolveTriageCommand(undefined)).resolves.toBe("t3 triage");
- await expect(resolveTriageCommand({} as DesktopBridge)).resolves.toBe("t3 triage");
+ await expect(resolveTriageCommand(undefined)).resolves.toBe("ada triage");
+ await expect(resolveTriageCommand({} as DesktopBridge)).resolves.toBe("ada triage");
await expect(resolveTriageCommand(desktopWith(async () => notOnPath(null)))).resolves.toBe(
- "t3 triage",
+ "ada triage",
);
const staleWindowsPathEntry = { ...notOnPath(null), supported: true, onPath: true };
await expect(
resolveTriageCommand(desktopWith(async () => staleWindowsPathEntry)),
- ).resolves.toBe("t3 triage");
+ ).resolves.toBe("ada triage");
await expect(
resolveTriageCommand(desktopWith(() => Promise.reject(new Error("ipc closed")))),
- ).resolves.toBe("t3 triage");
+ ).resolves.toBe("ada triage");
});
});
diff --git a/apps/web/src/lib/bootError.ts b/apps/web/src/lib/bootError.ts
index d6217473a660b..486265023fc92 100644
--- a/apps/web/src/lib/bootError.ts
+++ b/apps/web/src/lib/bootError.ts
@@ -3,7 +3,7 @@ import type { DesktopBridge, DesktopUpdateState } from "@t3tools/contracts";
// Boot code loads before any package resolves, so it repeats APP_NAME and CLI_RELEASE_REPOSITORY from @t3tools/shared.
const APP_NAME = "Ada";
const REPOSITORY_URL = "https://github.com/jayleaton/t3code";
-const FALLBACK_TRIAGE_COMMAND = "t3 triage";
+const FALLBACK_TRIAGE_COMMAND = "ada triage";
const DOWNLOAD_URL = `${REPOSITORY_URL}/releases`;
const ISSUE_URL = `${REPOSITORY_URL}/issues/new`;
const LAST_FAILURE_KEY = "t3code:boot-failed-at";
@@ -26,12 +26,13 @@ function launcherCommand(launcherPath: string) {
: `'${launcherPath.replaceAll("'", `'"'"'`)}'`;
}
-/** Desktop can run its bundled launcher; everything else falls back to `t3` on PATH. */
+/** Desktop can run its bundled launcher; everything else falls back to `ada` on PATH. */
export async function resolveTriageCommand(bridge: DesktopBridge | undefined) {
try {
const state = await bridge?.cliCommand.getState();
// Windows reports onPath from its PATH entry alone; only an existing launcher proves it runs.
if (state?.launcherPath) {
+ // onPath reports the `t3` link; `ada` beside it is a best-effort alias.
return state.onPath ? "t3 triage" : `${launcherCommand(state.launcherPath)} triage`;
}
} catch (error) {
diff --git a/apps/web/src/state/managedPolicy.ts b/apps/web/src/state/managedPolicy.ts
index 4e588b3796012..1ca30648b46a5 100644
--- a/apps/web/src/state/managedPolicy.ts
+++ b/apps/web/src/state/managedPolicy.ts
@@ -1,4 +1,5 @@
import type { EnvironmentId, ManagedPolicySummary, ProviderDriverKind } from "@t3tools/contracts";
+import { APP_NAME } from "@t3tools/shared/branding";
import { useServerConfigs } from "./entities";
import { usePrimaryEnvironmentId } from "./environments";
@@ -30,13 +31,11 @@ export function firstManagedDenial(
return undefined;
}
-/** What usage-data notices say when the policy turns product analytics off. */
-export function managedTelemetryOffMessage(
- policy: ManagedPolicySummary | undefined,
-): string | undefined {
+/** What usage-data notices say; a policy can only turn product analytics off. */
+export function usageDataNotice(policy: ManagedPolicySummary | undefined): string {
return policy?.limits?.telemetry === false
? `${policy.organization} turned off anonymous usage data.`
- : undefined;
+ : `${APP_NAME} doesn't collect usage data unless you turn it on with T3CODE_TELEMETRY_ENABLED.`;
}
export interface ManagedInstanceLocks {
diff --git a/apps/web/src/themeBoot.test.ts b/apps/web/src/themeBoot.test.ts
index 8341978986bbe..ad970a71aa264 100644
--- a/apps/web/src/themeBoot.test.ts
+++ b/apps/web/src/themeBoot.test.ts
@@ -153,12 +153,12 @@ describe("index.html boot script", () => {
}> = [
{ name: "no stored preference on a dark OS", storage: {}, prefersDark: true },
{
- name: "T3 Chat follows a dark OS",
+ name: "Orchid follows a dark OS",
storage: { [THEME_STORAGE_KEY]: "t3-chat", [THEME_FOLLOW_SYSTEM_STORAGE_KEY]: "true" },
prefersDark: true,
},
{
- name: "an explicit global dark mode applies to T3 Chat",
+ name: "an explicit global dark mode applies to Orchid",
storage: {
[THEME_STORAGE_KEY]: "t3-chat",
[THEME_APPEARANCE_MODE_STORAGE_KEY]: "dark",
@@ -192,7 +192,7 @@ describe("index.html boot script", () => {
prefersDark: true,
},
{
- name: "legacy t3-chat-dark resolves to dark T3 Chat",
+ name: "legacy t3-chat-dark resolves to dark Orchid",
storage: { [THEME_STORAGE_KEY]: "t3-chat-dark" },
prefersDark: true,
},
diff --git a/assets/README.md b/assets/README.md
index f03136d3231bc..2caecbf93d089 100644
--- a/assets/README.md
+++ b/assets/README.md
@@ -1,67 +1,23 @@
# Brand icons
-The three Icon Composer projects are the source of truth for full application icons:
+`agents/pip.svg` is the hand-edited source for Ada's mark, Pip, and every icon is generated from it. `agents/pip-lockup-{dark,light}.{svg,png}` are the approved wordmark lockups, used as-is by the README and, through the export, the social card.
-- `dev/app-icon.icon`
-- `nightly/app-icon.icon`
-- `prod/app-icon.icon`
+The three Icon Composer projects give each release channel its backdrop:
-Each project uses `text.svg` for the T3 mark and `background.svg` when the background is a vector layer. Additional layers use semantic names that describe their role and placement.
+- `dev/app-icon.icon`: blueprint
+- `nightly/app-icon.icon`: night sky
+- `prod/app-icon.icon`: solid navy
-Run `vp run icons:export` from the repository root to regenerate the tracked iOS, Linux, Windows, and web assets. The development web exports are also copied to `apps/web/public` for the browser favicon, web app manifest icons, and splash screen. Run `vp run icons:check` to verify that the generated assets and public copies match their sources without changing files.
+Each project draws Pip from its own `Assets/pip.svg`, which the export writes from `agents/pip.svg` in that channel's colour. Edit the master, not these copies.
-Exporting requires Icon Composer 2 or newer on macOS. The script selects the newest compatible exporter from Xcode or a standalone Icon Composer installation and pins design generation 26. Set `ICON_COMPOSER_TOOL` to the full path of `Icon Composer.app/Contents/Executables/ictool` to override automatic discovery.
+Run `vp run icons:export` from the repository root to regenerate the tracked iOS, macOS, Linux, Windows, and web assets, plus the fork's `agents/` set, `apps/web/public/brand-mark.png`, and the marketing favicons, icons, and social card. The development web exports are also copied to `apps/web/public` for the browser favicon and web app manifest icons. Run `vp run icons:check` to verify that every generated asset matches its source without changing files.
-## macOS exports
+Exporting requires Icon Composer 2 or newer on macOS. The script selects the newest compatible exporter from Xcode or a standalone Icon Composer installation and pins design generation 26. Set `ICON_COMPOSER_TOOL` to the full path of `Icon Composer.app/Contents/Executables/ictool` to override automatic discovery. The social card's text uses the system's Helvetica Neue.
-Icon Composer's command-line exporter does not expose the `macOS pre-Tahoe` preset. A plain command-line `macOS` export is full bleed and is not suitable for the desktop app, so the export script intentionally leaves the tracked macOS PNGs unchanged and prints a reminder after every run.
+Icon Composer's command-line exporter has no `macOS pre-Tahoe` preset; its `macOS` export is full bleed. The export therefore places the rendered icon on Apple's classic safe area, an 824×824 body inset 100 pixels on a 1024×1024 canvas, without Icon Composer's native shadow.
-After changing an Icon Composer project, open it in Icon Composer and export the macOS PNG with exactly these settings:
+Do not edit the generated PNG, ICO, or WebP files directly.
-- Platform: `macOS pre-Tahoe`
-- Appearance: `Default`
-- Size: `1024pt`
-- Scale: `1×`
+## Mobile launcher, splash, and widget artwork
-Save the three exports to:
-
-- `dev/app-icon.icon` -> `dev/blueprint-macos-1024.png`
-- `nightly/app-icon.icon` -> `nightly/nightly-macos-1024.png`
-- `prod/app-icon.icon` -> `prod/black-macos-1024.png`
-
-The result must be a 1024×1024 PNG with the classic macOS safe area: the opaque icon body is 824×824, inset 100 pixels on every side, with only the native Icon Composer shadow extending into the surrounding transparent canvas.
-
-To have Codex perform the native exports, paste this prompt into a task opened at the repository root:
-
-```text
-Use [@Computer](plugin://computer-use@openai-bundled) and the Icon Composer app to export the three macOS app icons in this repository.
-
-For each project below, use Platform: macOS pre-Tahoe, Appearance: Default, Size: 1024pt, and Scale: 1×, then save the PNG to the exact destination:
-
-- assets/dev/app-icon.icon -> assets/dev/blueprint-macos-1024.png
-- assets/nightly/app-icon.icon -> assets/nightly/nightly-macos-1024.png
-- assets/prod/app-icon.icon -> assets/prod/black-macos-1024.png
-
-Do not resize, composite, or otherwise post-process the exported PNGs.
-
-Verify every result is 1024×1024 and has the classic macOS safe area: an 824×824 opaque body inset 100px on every side, with only Icon Composer's native shadow extending beyond it.
-```
-
-Do not edit the generated PNG or ICO files directly.
-
-## Android launcher and splash artwork
-
-Android masks the central 72dp of a 108dp adaptive canvas, and the Android 12+ splash screen masks
-the central two thirds of a 288dp canvas, so the Icon Composer exports cannot be used directly:
-their rounded-square silhouette gets framed again and the wordmark is cropped. The Android artwork
-is instead rendered from the same Icon Composer SVG sources by `vp run icons:export:android`:
-
-- `apps/mobile/assets/android-icon-foreground.png`: the shared transparent wordmark, sized to stay
- inside the safe zone
-- `apps/mobile/assets/android-icon-background-dev.png` and `-nightly.png`: full-bleed variant
- artwork (blueprint grid and annotations; night sky and clouds). Production uses a solid color.
-- `apps/mobile/assets/android-splash-icon-*.png`: the two layers composed into one 288dp image, so
- the splash mask reproduces the launcher icon's framing.
-
-Rerun the export after changing a layer SVG. `android-icon-mark.png` remains a flat silhouette for
-Android's monochrome themed icon.
+`vp run icons:export:android` renders the mobile app's assets from `agents/pip.svg` into `apps/mobile/assets/agents/` and the widget's template mark into `apps/mobile/assets/widget/PipMark.svg`. iOS gets a full-bleed navy square because it applies its own mask. Android masks the central 72dp of a 108dp adaptive canvas and the Android 12+ splash screen masks the central two thirds of a 288dp canvas, so Android gets Pip alone, sized to stay inside those safe zones over a navy background. Every app variant uses the same set.
diff --git a/assets/agents/apple-touch-icon.png b/assets/agents/apple-touch-icon.png
index d09cfd24614e2..761c5949d68e5 100644
Binary files a/assets/agents/apple-touch-icon.png and b/assets/agents/apple-touch-icon.png differ
diff --git a/assets/agents/favicon-16x16.png b/assets/agents/favicon-16x16.png
index bacf8fa640a4b..427bbe125ea8a 100644
Binary files a/assets/agents/favicon-16x16.png and b/assets/agents/favicon-16x16.png differ
diff --git a/assets/agents/favicon-32x32.png b/assets/agents/favicon-32x32.png
index 48ed2a804ea7e..6eff5df10a9b5 100644
Binary files a/assets/agents/favicon-32x32.png and b/assets/agents/favicon-32x32.png differ
diff --git a/assets/agents/favicon.ico b/assets/agents/favicon.ico
index ff018ba62d645..9e249762a4ff2 100644
Binary files a/assets/agents/favicon.ico and b/assets/agents/favicon.ico differ
diff --git a/assets/agents/icon-192x192.png b/assets/agents/icon-192x192.png
index e4642bf746c47..fe58dbc644de8 100644
Binary files a/assets/agents/icon-192x192.png and b/assets/agents/icon-192x192.png differ
diff --git a/assets/agents/icon-512x512.png b/assets/agents/icon-512x512.png
index 9280ea3167f8c..8495d609e91f9 100644
Binary files a/assets/agents/icon-512x512.png and b/assets/agents/icon-512x512.png differ
diff --git a/assets/agents/icon.png b/assets/agents/icon.png
index 63bf58a0e114c..28c36e309b9d6 100644
Binary files a/assets/agents/icon.png and b/assets/agents/icon.png differ
diff --git a/assets/agents/pip-lockup-dark.png b/assets/agents/pip-lockup-dark.png
new file mode 100644
index 0000000000000..6bf48f8ad927b
Binary files /dev/null and b/assets/agents/pip-lockup-dark.png differ
diff --git a/assets/agents/pip-lockup-dark.svg b/assets/agents/pip-lockup-dark.svg
new file mode 100644
index 0000000000000..8abf3478d6886
--- /dev/null
+++ b/assets/agents/pip-lockup-dark.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/agents/pip-lockup-light.png b/assets/agents/pip-lockup-light.png
new file mode 100644
index 0000000000000..28f9577028275
Binary files /dev/null and b/assets/agents/pip-lockup-light.png differ
diff --git a/assets/agents/pip-lockup-light.svg b/assets/agents/pip-lockup-light.svg
new file mode 100644
index 0000000000000..c0bd60885bf9d
--- /dev/null
+++ b/assets/agents/pip-lockup-light.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/agents/pip.svg b/assets/agents/pip.svg
new file mode 100644
index 0000000000000..c73a798ef9ab0
--- /dev/null
+++ b/assets/agents/pip.svg
@@ -0,0 +1 @@
+
diff --git a/assets/agents/source.png b/assets/agents/source.png
deleted file mode 100644
index fcff557ef6565..0000000000000
Binary files a/assets/agents/source.png and /dev/null differ
diff --git a/assets/agents/windows.ico b/assets/agents/windows.ico
index 8990e2635b055..9e249762a4ff2 100644
Binary files a/assets/agents/windows.ico and b/assets/agents/windows.ico differ
diff --git a/assets/dev/app-icon.icon/Assets/pip.svg b/assets/dev/app-icon.icon/Assets/pip.svg
new file mode 100644
index 0000000000000..6f96e6692bddb
--- /dev/null
+++ b/assets/dev/app-icon.icon/Assets/pip.svg
@@ -0,0 +1 @@
+
diff --git a/assets/dev/app-icon.icon/Assets/text.svg b/assets/dev/app-icon.icon/Assets/text.svg
deleted file mode 100644
index 0b1825f2ef471..0000000000000
--- a/assets/dev/app-icon.icon/Assets/text.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/assets/dev/app-icon.icon/icon.json b/assets/dev/app-icon.icon/icon.json
index ff7d43d781120..20f54bb43e78f 100644
--- a/assets/dev/app-icon.icon/icon.json
+++ b/assets/dev/app-icon.icon/icon.json
@@ -7,11 +7,11 @@
"layers": [
{
"glass": true,
- "image-name": "text.svg",
- "name": "Text",
+ "image-name": "pip.svg",
+ "name": "Pip",
"position": {
- "scale": 8.5,
- "translation-in-points": [0, 0]
+ "scale": 8.4,
+ "translation-in-points": [0, -24]
}
},
{
diff --git a/assets/dev/blueprint-ios-1024.png b/assets/dev/blueprint-ios-1024.png
index a53c8d19aa83a..3ed88f700e7d8 100644
Binary files a/assets/dev/blueprint-ios-1024.png and b/assets/dev/blueprint-ios-1024.png differ
diff --git a/assets/dev/blueprint-macos-1024.png b/assets/dev/blueprint-macos-1024.png
index 68a567058be10..10d4005727300 100644
Binary files a/assets/dev/blueprint-macos-1024.png and b/assets/dev/blueprint-macos-1024.png differ
diff --git a/assets/dev/blueprint-universal-1024.png b/assets/dev/blueprint-universal-1024.png
index a53c8d19aa83a..3ed88f700e7d8 100644
Binary files a/assets/dev/blueprint-universal-1024.png and b/assets/dev/blueprint-universal-1024.png differ
diff --git a/assets/dev/blueprint-web-apple-touch-180.png b/assets/dev/blueprint-web-apple-touch-180.png
index 3eed25ea6b785..d1f37f18c8c4f 100644
Binary files a/assets/dev/blueprint-web-apple-touch-180.png and b/assets/dev/blueprint-web-apple-touch-180.png differ
diff --git a/assets/dev/blueprint-web-favicon-16x16.png b/assets/dev/blueprint-web-favicon-16x16.png
index a3431b8c6dfef..161703c169a31 100644
Binary files a/assets/dev/blueprint-web-favicon-16x16.png and b/assets/dev/blueprint-web-favicon-16x16.png differ
diff --git a/assets/dev/blueprint-web-favicon-32x32.png b/assets/dev/blueprint-web-favicon-32x32.png
index 862f7629971fa..bb18b62def5d3 100644
Binary files a/assets/dev/blueprint-web-favicon-32x32.png and b/assets/dev/blueprint-web-favicon-32x32.png differ
diff --git a/assets/dev/blueprint-web-favicon.ico b/assets/dev/blueprint-web-favicon.ico
index 750da22602eec..571b446bec91d 100644
Binary files a/assets/dev/blueprint-web-favicon.ico and b/assets/dev/blueprint-web-favicon.ico differ
diff --git a/assets/dev/blueprint-web-icon-192x192.png b/assets/dev/blueprint-web-icon-192x192.png
index 3e2637386b1d1..1b395ad79a07c 100644
Binary files a/assets/dev/blueprint-web-icon-192x192.png and b/assets/dev/blueprint-web-icon-192x192.png differ
diff --git a/assets/dev/blueprint-web-icon-512x512.png b/assets/dev/blueprint-web-icon-512x512.png
index 1fac754a327fd..ac8802bc6fc1b 100644
Binary files a/assets/dev/blueprint-web-icon-512x512.png and b/assets/dev/blueprint-web-icon-512x512.png differ
diff --git a/assets/dev/blueprint-windows.ico b/assets/dev/blueprint-windows.ico
index 750da22602eec..571b446bec91d 100644
Binary files a/assets/dev/blueprint-windows.ico and b/assets/dev/blueprint-windows.ico differ
diff --git a/assets/nightly/app-icon.icon/Assets/pip.svg b/assets/nightly/app-icon.icon/Assets/pip.svg
new file mode 100644
index 0000000000000..6f96e6692bddb
--- /dev/null
+++ b/assets/nightly/app-icon.icon/Assets/pip.svg
@@ -0,0 +1 @@
+
diff --git a/assets/nightly/app-icon.icon/Assets/text.svg b/assets/nightly/app-icon.icon/Assets/text.svg
deleted file mode 100644
index 0b1825f2ef471..0000000000000
--- a/assets/nightly/app-icon.icon/Assets/text.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/assets/nightly/app-icon.icon/icon.json b/assets/nightly/app-icon.icon/icon.json
index eb48d26b4a521..06722c561c74c 100644
--- a/assets/nightly/app-icon.icon/icon.json
+++ b/assets/nightly/app-icon.icon/icon.json
@@ -7,11 +7,11 @@
"layers": [
{
"glass": true,
- "image-name": "text.svg",
- "name": "Text",
+ "image-name": "pip.svg",
+ "name": "Pip",
"position": {
- "scale": 8.5,
- "translation-in-points": [0, 0]
+ "scale": 8.4,
+ "translation-in-points": [0, -24]
}
},
{
diff --git a/assets/nightly/nightly-ios-1024.png b/assets/nightly/nightly-ios-1024.png
index 42ce5589e9cac..a9cf4b09080fc 100644
Binary files a/assets/nightly/nightly-ios-1024.png and b/assets/nightly/nightly-ios-1024.png differ
diff --git a/assets/nightly/nightly-macos-1024.png b/assets/nightly/nightly-macos-1024.png
index 1beacd9f34ade..a0e45a2d50535 100644
Binary files a/assets/nightly/nightly-macos-1024.png and b/assets/nightly/nightly-macos-1024.png differ
diff --git a/assets/nightly/nightly-universal-1024.png b/assets/nightly/nightly-universal-1024.png
index 42ce5589e9cac..a9cf4b09080fc 100644
Binary files a/assets/nightly/nightly-universal-1024.png and b/assets/nightly/nightly-universal-1024.png differ
diff --git a/assets/nightly/nightly-web-apple-touch-180.png b/assets/nightly/nightly-web-apple-touch-180.png
index f09a169458ab4..ab697564aa59a 100644
Binary files a/assets/nightly/nightly-web-apple-touch-180.png and b/assets/nightly/nightly-web-apple-touch-180.png differ
diff --git a/assets/nightly/nightly-web-favicon-16x16.png b/assets/nightly/nightly-web-favicon-16x16.png
index 20208f5f36951..8cc9e0c87cc9d 100644
Binary files a/assets/nightly/nightly-web-favicon-16x16.png and b/assets/nightly/nightly-web-favicon-16x16.png differ
diff --git a/assets/nightly/nightly-web-favicon-32x32.png b/assets/nightly/nightly-web-favicon-32x32.png
index b9008d518bce0..74968175bccce 100644
Binary files a/assets/nightly/nightly-web-favicon-32x32.png and b/assets/nightly/nightly-web-favicon-32x32.png differ
diff --git a/assets/nightly/nightly-web-favicon.ico b/assets/nightly/nightly-web-favicon.ico
index b6a0b43b93d2e..d76abcfcc4011 100644
Binary files a/assets/nightly/nightly-web-favicon.ico and b/assets/nightly/nightly-web-favicon.ico differ
diff --git a/assets/nightly/nightly-web-icon-192x192.png b/assets/nightly/nightly-web-icon-192x192.png
index 95e9256dc8abb..59228ef9d890d 100644
Binary files a/assets/nightly/nightly-web-icon-192x192.png and b/assets/nightly/nightly-web-icon-192x192.png differ
diff --git a/assets/nightly/nightly-web-icon-512x512.png b/assets/nightly/nightly-web-icon-512x512.png
index 6ce057fba4a67..8dda1571c8729 100644
Binary files a/assets/nightly/nightly-web-icon-512x512.png and b/assets/nightly/nightly-web-icon-512x512.png differ
diff --git a/assets/nightly/nightly-windows.ico b/assets/nightly/nightly-windows.ico
index b6a0b43b93d2e..d76abcfcc4011 100644
Binary files a/assets/nightly/nightly-windows.ico and b/assets/nightly/nightly-windows.ico differ
diff --git a/assets/prod/app-icon.icon/Assets/pip.svg b/assets/prod/app-icon.icon/Assets/pip.svg
new file mode 100644
index 0000000000000..c73a798ef9ab0
--- /dev/null
+++ b/assets/prod/app-icon.icon/Assets/pip.svg
@@ -0,0 +1 @@
+
diff --git a/assets/prod/app-icon.icon/Assets/text.svg b/assets/prod/app-icon.icon/Assets/text.svg
deleted file mode 100644
index 0b1825f2ef471..0000000000000
--- a/assets/prod/app-icon.icon/Assets/text.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/assets/prod/app-icon.icon/icon.json b/assets/prod/app-icon.icon/icon.json
index 6976a6a724c81..48da42d07cb5f 100644
--- a/assets/prod/app-icon.icon/icon.json
+++ b/assets/prod/app-icon.icon/icon.json
@@ -1,16 +1,16 @@
{
"fill": {
- "solid": "display-p3:0.00000,0.00000,0.00000,1.00000"
+ "solid": "srgb:0.06667,0.09804,0.14510,1.00000"
},
"groups": [
{
"layers": [
{
- "image-name": "text.svg",
- "name": "Text",
+ "image-name": "pip.svg",
+ "name": "Pip",
"position": {
- "scale": 8.5,
- "translation-in-points": [0, 0]
+ "scale": 8.4,
+ "translation-in-points": [0, -24]
}
}
],
diff --git a/assets/prod/black-ios-1024.png b/assets/prod/black-ios-1024.png
index bfc80410aadc5..f5e15607d7cf1 100644
Binary files a/assets/prod/black-ios-1024.png and b/assets/prod/black-ios-1024.png differ
diff --git a/assets/prod/black-macos-1024.png b/assets/prod/black-macos-1024.png
index 6a0fe10d3dacc..28c36e309b9d6 100644
Binary files a/assets/prod/black-macos-1024.png and b/assets/prod/black-macos-1024.png differ
diff --git a/assets/prod/black-universal-1024.png b/assets/prod/black-universal-1024.png
index bfc80410aadc5..f5e15607d7cf1 100644
Binary files a/assets/prod/black-universal-1024.png and b/assets/prod/black-universal-1024.png differ
diff --git a/assets/prod/logo.svg b/assets/prod/logo.svg
deleted file mode 100644
index 61b48db5af1a5..0000000000000
--- a/assets/prod/logo.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/assets/prod/t3-black-web-apple-touch-180.png b/assets/prod/t3-black-web-apple-touch-180.png
index 327a8ac55fafa..761c5949d68e5 100644
Binary files a/assets/prod/t3-black-web-apple-touch-180.png and b/assets/prod/t3-black-web-apple-touch-180.png differ
diff --git a/assets/prod/t3-black-web-favicon-16x16.png b/assets/prod/t3-black-web-favicon-16x16.png
index 6ba6d92c03791..427bbe125ea8a 100644
Binary files a/assets/prod/t3-black-web-favicon-16x16.png and b/assets/prod/t3-black-web-favicon-16x16.png differ
diff --git a/assets/prod/t3-black-web-favicon-32x32.png b/assets/prod/t3-black-web-favicon-32x32.png
index fb354d60ace97..6eff5df10a9b5 100644
Binary files a/assets/prod/t3-black-web-favicon-32x32.png and b/assets/prod/t3-black-web-favicon-32x32.png differ
diff --git a/assets/prod/t3-black-web-favicon.ico b/assets/prod/t3-black-web-favicon.ico
index 5fac0d8b24ea6..9e249762a4ff2 100644
Binary files a/assets/prod/t3-black-web-favicon.ico and b/assets/prod/t3-black-web-favicon.ico differ
diff --git a/assets/prod/t3-black-web-icon-192x192.png b/assets/prod/t3-black-web-icon-192x192.png
index aa7944053b5d8..fe58dbc644de8 100644
Binary files a/assets/prod/t3-black-web-icon-192x192.png and b/assets/prod/t3-black-web-icon-192x192.png differ
diff --git a/assets/prod/t3-black-web-icon-512x512.png b/assets/prod/t3-black-web-icon-512x512.png
index 597cfcc592370..8495d609e91f9 100644
Binary files a/assets/prod/t3-black-web-icon-512x512.png and b/assets/prod/t3-black-web-icon-512x512.png differ
diff --git a/assets/prod/t3-black-windows.ico b/assets/prod/t3-black-windows.ico
index 5fac0d8b24ea6..9e249762a4ff2 100644
Binary files a/assets/prod/t3-black-windows.ico and b/assets/prod/t3-black-windows.ico differ
diff --git a/docs/user/background-service.md b/docs/user/background-service.md
index b0bdaf726824f..0971a35bda176 100644
--- a/docs/user/background-service.md
+++ b/docs/user/background-service.md
@@ -40,7 +40,7 @@ installing one.
`ada uninstall` removes the background service, the `ada` launcher, and the
downloaded versions after showing you the list and asking once. Your projects,
threads, and settings under `~/.t3/userdata` are kept, along with `service.env`
-under T3 home. Pass `--yes` from a script.
+under Ada home. Pass `--yes` from a script.
## Local network access
@@ -59,7 +59,7 @@ network. `ada status` says so, and `ada up --no-lan` turns it off. Any
## Configure the service environment
-Put custom environment variables in `service.env` under the service's T3 home
+Put custom environment variables in `service.env` under the service's Ada home
directory, normally `~/.t3/service.env`. This file survives service installation
and updates. For example:
@@ -79,7 +79,7 @@ For a service installed before env-file support, run `ada service install` once
with an up-to-date CLI.
A missing file is ignored; other read failures stop service startup.
If the file contains credentials, restrict access to that file with `chmod 600`
-(for the default T3 home, `chmod 600 ~/.t3/service.env`).
+(for the default Ada home, `chmod 600 ~/.t3/service.env`).
### Ada webhooks without the desktop app
diff --git a/docs/user/faq.md b/docs/user/faq.md
index 68bca6447c233..d96a64001b899 100644
--- a/docs/user/faq.md
+++ b/docs/user/faq.md
@@ -59,7 +59,7 @@ No. Ada is a serious developer tool. Locally runnable models are not capable of
## Does my code go to Ada servers?
-No. Your code and prompts go from your machine to your provider (Anthropic, OpenAI, etc.), not to us. Your devices connect straight to your machine over your LAN or Tailscale. Ada does send basic product usage events (provider, model, token totals, that kind of thing). No prompts, no file contents. Set `T3CODE_TELEMETRY_ENABLED=false` if you want it off. [Product usage data](./telemetry.md)
+No. Your code and prompts go from your machine to your provider (Anthropic, OpenAI, etc.), not to us. Your devices connect straight to your machine over your LAN or Tailscale. Ada doesn't collect usage data unless you turn it on with `T3CODE_TELEMETRY_ENABLED=true`. [Product usage data](./telemetry.md)
## Worktrees are eating my disk. How do I clean them up?
diff --git a/docs/user/mobile-notifications.md b/docs/user/mobile-notifications.md
index b7c15f79da510..322e1c8dfa839 100644
--- a/docs/user/mobile-notifications.md
+++ b/docs/user/mobile-notifications.md
@@ -1,5 +1,5 @@
# Mobile notifications
-Push notifications, Live Activities, Android Live Updates, and the **Agent Activity** widget are not available. They were delivered through T3 Connect, which has been removed, and a direct or Tailscale connection cannot wake a phone.
+Push notifications, Live Activities, Android Live Updates, and the **Agent Activity** widget are not available in Ada. A direct or Tailscale connection cannot wake a phone.
To see what your agents are doing, open Ada on your phone. It connects to your environments and shows each thread's current state, including work that finished, failed, or is waiting for your approval or input.
diff --git a/docs/user/outside-agents.md b/docs/user/outside-agents.md
index 04eb257de7b5e..c9125663927df 100644
--- a/docs/user/outside-agents.md
+++ b/docs/user/outside-agents.md
@@ -125,7 +125,7 @@ On the machine that runs the environment, `ada thread` uses the same tools
without a sign-in:
```sh
-id=$(t3 thread start . "Find why the tests are slow")
+id=$(ada thread start . "Find why the tests are slow")
ada thread send "$id" "Now fix it" --wait
ada thread show "$id"
ada thread list
diff --git a/docs/user/project-settings.md b/docs/user/project-settings.md
index 74997d917fcd4..4142a82aea29c 100644
--- a/docs/user/project-settings.md
+++ b/docs/user/project-settings.md
@@ -237,7 +237,7 @@ releases and the `ada` package on npm don't include `watch`, so if `ada watch`
reports an unknown command, that `ada` is too old.
- **Desktop app:** the app keeps its own launcher at `~/.t3/bin/t3`, or
- `%USERPROFILE%\.t3\bin\t3.cmd` on Windows (under your T3 home if you changed
+ `%USERPROFILE%\.t3\bin\t3.cmd` on Windows (under your Ada home if you changed
it). [The `ada` command](./install.md#the-t3-command) explains how to put it on
your `PATH`.
- **Server without the desktop app:** use the standalone `ada` CLI built with
@@ -301,7 +301,7 @@ applies when the project and environment are both on **Inherit**.
## Worktree location
-New worktrees go in the `worktrees` folder of the T3 home directory. To put them somewhere else,
+New worktrees go in the `worktrees` folder of the Ada home directory. To put them somewhere else,
such as another drive, set **Settings → Worktrees → Worktree location** to an absolute path like
`D:\worktrees` or `~/worktrees`. The setting is per machine. Existing worktrees stay where they
are, and cleanup covers both the default folder and the custom one.
@@ -310,12 +310,12 @@ are, and cleanup covers both the default folder and the custom one.
Fast worktree checkout is a beta. Turn it on for each Mac in **Settings → Labs → Fast worktree
checkout**. Ada then keeps a few recent checkouts of each repository in the `caches` folder of
-the T3 home directory. A new worktree is cloned from one of them with APFS copy-on-write, which is
+the Ada home directory. A new worktree is cloned from one of them with APFS copy-on-write, which is
about twice as fast as writing every file and makes the first `git status` in it fast as well.
Turning it off deletes the cache.
The first worktree of a repository uses Git's normal checkout and fills the cache. It needs Git 2.42
-or newer. Git's normal checkout is also used for worktrees on a different drive from the T3 home
+or newer. Git's normal checkout is also used for worktrees on a different drive from the Ada home
directory, sparse checkouts, repositories whose attributes use filters such as Git LFS, and
repositories whose checkout settings changed.
diff --git a/docs/user/providers-acp.md b/docs/user/providers-acp.md
index 9c21e3e3d329e..2702ce1576127 100644
--- a/docs/user/providers-acp.md
+++ b/docs/user/providers-acp.md
@@ -44,7 +44,7 @@ without expanding shell expressions.
Registry agents always run on the machine that hosts your Ada server. That stays true when you
connect through `app.t3.codes` or from another device.
-Agents install under `tools///` inside T3 home. Ada verifies SHA-256 when the Registry entry
+Agents install under `tools///` inside Ada home. Ada verifies SHA-256 when the Registry entry
provides one; entries without a checksum retain the Registry's HTTPS distribution guarantee.
Registry `npx` and `uvx` packages use Ada-owned npm prefixes and Python tool directories at the exact
version published by the Registry. Their commands are available in a new server terminal for
diff --git a/docs/user/remote-access.md b/docs/user/remote-access.md
index 05ff7a680057c..5f424c6da01a7 100644
--- a/docs/user/remote-access.md
+++ b/docs/user/remote-access.md
@@ -221,7 +221,7 @@ directly. Every other device, and the desktop app for other environments,
streams them from the host. Agents keep using them while no device is
connected, and `localhost` addresses reach servers on the host.
-The first tab downloads a headless Chrome, about 120 MB, into the T3 home. It
+The first tab downloads a headless Chrome, about 120 MB, into the Ada home. It
is the same browser [HTML renders](html-renders.md) use, so a host downloads it
only once. Some Linux hosts need [setup](#browser-host-setup) before it can
start.
@@ -281,7 +281,7 @@ If you need to run as root, or cannot enable the sandbox on your host, set
the server. This disables Chrome's sandbox. For a manual launch:
```sh
-T3CODE_SERVER_BROWSER_SANDBOX=0 t3 serve
+T3CODE_SERVER_BROWSER_SANDBOX=0 ada serve
```
For a systemd service, add `Environment=T3CODE_SERVER_BROWSER_SANDBOX=0` under
@@ -778,7 +778,7 @@ desktop app, open **Settings → Environments** and switch off **Local
environment**. Ada restarts without a local server: no local agents or terminals run, WSL
backends stay off, and other devices can no longer connect to this computer. Your projects,
history, and saved connections are kept, and you keep working through pairing or SSH.
-If a [background service](./background-service.md) on this computer uses the same T3 home, the
+If a [background service](./background-service.md) on this computer uses the same Ada home, the
app still treats it as this computer: **Open in** and file reveal for its projects run here,
whichever connection you reach it through.
diff --git a/docs/user/source-control.md b/docs/user/source-control.md
index 24520502586b3..4d68dc35ac08c 100644
--- a/docs/user/source-control.md
+++ b/docs/user/source-control.md
@@ -99,7 +99,7 @@ export T3CODE_BITBUCKET_API_TOKEN="your-token"
For a background service, put these `KEY=VALUE` entries in
[`service.env`](./background-service.md#configure-the-service-environment)
-under T3 home, then run `ada service restart`. Service installation and updates
+under Ada home, then run `ada service restart`. Service installation and updates
preserve that file.
### Azure DevOps
diff --git a/docs/user/telemetry.md b/docs/user/telemetry.md
index c9af3592ba1cc..ac052c5b6c6c4 100644
--- a/docs/user/telemetry.md
+++ b/docs/user/telemetry.md
@@ -1,6 +1,7 @@
# Product usage data
-The Ada server sends product usage events to the endpoint at `ingest.t3.codes`,
+Ada doesn't collect usage data unless you turn it on with `T3CODE_TELEMETRY_ENABLED=true`.
+When it is on, the server sends product usage events to the endpoint at `ingest.t3.codes`,
associated with a hashed account or installation identifier. To count how many installations one person
uses, the server also sends hashed account identifiers: your OpenAI and
Claude accounts when you are signed in, and a random identifier for each device that connects. The endpoint keeps a copy of each
@@ -12,11 +13,11 @@ are sent only when they appear in a provider's public model list.
Product events do not include prompts, responses, file contents, authentication tokens, conversation IDs,
raw provider events, or child-agent output.
-## Turn it off
+## Turn it on
-To disable product events from the server, set `T3CODE_TELEMETRY_ENABLED=false` in its
-environment before starting it. An administrator can also turn them off in the server and desktop
-app with a [managed policy](./managed-policy.md#other-capabilities).
+To send product events from the server, set `T3CODE_TELEMETRY_ENABLED=true` in its
+environment before starting it. An administrator can keep them off in the server and desktop
+app with a [managed policy](./managed-policy.md#other-capabilities), which a variable cannot override.
The desktop app reads `T3CODE_TELEMETRY_ENABLED` from your shell profile (for example `~/.zshrc`) on macOS and
Linux, so export it there and restart the app. On Windows, set it as a user environment variable.
diff --git a/docs/user/updating.md b/docs/user/updating.md
index 56b193964d4a3..0158d82a671b3 100644
--- a/docs/user/updating.md
+++ b/docs/user/updating.md
@@ -117,7 +117,7 @@ update can roll back to the previous version. If the update still fails:
2. Check that you updated the server's machine, not only the device you are using.
3. For a command-line server, run `ada update ` with the exact version shown in the notice, then start it again.
-Only one server can use a T3 home directory at a time. If startup reports that
+Only one server can use a Ada home directory at a time. If startup reports that
another server owns it, stop that server before retrying, or use a separate home
directory and pair with the running server.
diff --git a/docs/user/usage.md b/docs/user/usage.md
index 2ba4c51af6fdc..45cf7d50b2df9 100644
--- a/docs/user/usage.md
+++ b/docs/user/usage.md
@@ -42,8 +42,8 @@ Use absolute paths or `~/` paths in the account's environment settings; relative
depend on each project's working directory and cannot be reliably discovered by Usage. Accounts
sharing a history directory count once.
-The server saves its first hostname in `/usage-host-id`, so a recreated container keeps
-its usage identity when T3 home is persisted. Set `T3CODE_HOST_ID` to choose the identity
+The server saves its first hostname in `/usage-host-id`, so a recreated container keeps
+its usage identity when Ada home is persisted. Set `T3CODE_HOST_ID` to choose the identity
explicitly.
When your app and server support different providers, usage totals may cover only the providers
diff --git a/packages/client-runtime/src/preview/serverBrowserStream.ts b/packages/client-runtime/src/preview/serverBrowserStream.ts
index 9710546bd3862..a498694567b24 100644
--- a/packages/client-runtime/src/preview/serverBrowserStream.ts
+++ b/packages/client-runtime/src/preview/serverBrowserStream.ts
@@ -1,4 +1,5 @@
// @effect-diagnostics globalTimers:off globalFetch:off - This browser and WebView transport runs without an Effect runtime.
+import { CLI_COMMAND } from "@t3tools/shared/branding";
import { type DeviceHubAccess, withDeviceHubQuery } from "../device/hubAccess.ts";
import {
PREVIEW_STREAM_HOST_SETUP_CLOSE_CODE,
@@ -460,7 +461,7 @@ const decodeHostSetup = (reason: string): PreviewStreamHostSetup => {
return { need: value.need, command: value.command };
}
} catch {}
- return { need: "sandbox", command: 'sudo env "PATH=$PATH" t3 browser setup' };
+ return { need: "sandbox", command: `sudo env "PATH=$PATH" ${CLI_COMMAND} browser setup` };
};
export const previewStreamHostSetupMessage = (setup: PreviewStreamHostSetup) =>
diff --git a/packages/contracts/src/peerLink.ts b/packages/contracts/src/peerLink.ts
index 76ab701d2cc83..81ccdd68b0699 100644
--- a/packages/contracts/src/peerLink.ts
+++ b/packages/contracts/src/peerLink.ts
@@ -41,7 +41,7 @@ export const PeerLinkCreateInput = Schema.Struct({
url: TrimmedNonEmptyString,
/** More addresses for the same peer, tried after `url`. */
alternateUrls: Schema.optionalKey(Schema.Array(TrimmedNonEmptyString)),
- /** A pairing code from the peer (`t3 pair` there, or its Connections settings). */
+ /** A pairing code from the peer (`ada pair` there, or its Connections settings). */
pairingCode: TrimmedNonEmptyString,
access: AuthMcpClientAccess,
/**
diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts
index c4ed2bf6ddb2e..e91cfc450ad92 100644
--- a/packages/contracts/src/settings.ts
+++ b/packages/contracts/src/settings.ts
@@ -1683,7 +1683,7 @@ export const ServerSettings = Schema.Struct({
branchNamingMode: BranchNamingMode.pipe(
Schema.withDecodingDefault(Effect.succeed("static" as const)),
),
- branchNamePrefix: TrimmedString.pipe(Schema.withDecodingDefault(Effect.succeed("t3"))),
+ branchNamePrefix: TrimmedString.pipe(Schema.withDecodingDefault(Effect.succeed("ada"))),
branchNameInstructions: TrimmedString.pipe(Schema.withDecodingDefault(Effect.succeed(""))),
removeAgentCreditsOnMerge: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
sourceControlWritingStyle: SourceControlWritingStyleSetting.pipe(
diff --git a/packages/contracts/src/t3ProjectFile.ts b/packages/contracts/src/t3ProjectFile.ts
index d09878344b8c8..37f43299676ab 100644
--- a/packages/contracts/src/t3ProjectFile.ts
+++ b/packages/contracts/src/t3ProjectFile.ts
@@ -49,7 +49,7 @@ export const T3ProjectFileScript = Schema.Struct({
stopOnSettle: Schema.optionalKey(
Schema.Boolean.annotate({
description:
- "When true, T3 stops this action's terminal and child processes when its thread settles.",
+ "When true, Ada stops this action's terminal and child processes when its thread settles.",
}),
),
async: Schema.optionalKey(
@@ -110,7 +110,7 @@ export const T3ProjectFile = Schema.Struct({
.check(Schema.isMaxLength(T3_PROJECT_FILE_MAX_SCRIPTS)),
),
}).annotate({
- title: "T3 project file",
+ title: "Ada project file",
description:
"Checked-in project configuration for Ada (t3.json at the repository root). See https://github.com/jayleaton/t3code for documentation.",
});
diff --git a/packages/provider-acp/src/server/AcpSessionRuntime.ts b/packages/provider-acp/src/server/AcpSessionRuntime.ts
index b1747ffba4f76..6ae7e21514f57 100644
--- a/packages/provider-acp/src/server/AcpSessionRuntime.ts
+++ b/packages/provider-acp/src/server/AcpSessionRuntime.ts
@@ -3,6 +3,7 @@ import * as NodeCrypto from "node:crypto";
import * as NodeFS from "node:fs";
import * as NodePath from "node:path";
+import { APP_NAME } from "@t3tools/shared/branding";
import * as Cause from "effect/Cause";
import * as Clock from "effect/Clock";
import * as Context from "effect/Context";
@@ -913,7 +914,7 @@ export function terminatePosixOwnedProcessTree(input: {
discover(table);
const byPid = new Map(table.map((entry) => [entry.pid, entry]));
const current = input.controller.identity(process.pid);
- if (current === undefined) throw fail("Cannot identify the current T3 process group");
+ if (current === undefined) throw fail(`Cannot identify the current ${APP_NAME} process group`);
const ledgerByPid = new Map(
[...ledger.values()].map((process) => [process.pid, process] as const),
);
diff --git a/packages/shared/src/cliRelease.ts b/packages/shared/src/cliRelease.ts
index 780f96702a5c5..a7c9cb5b06353 100644
--- a/packages/shared/src/cliRelease.ts
+++ b/packages/shared/src/cliRelease.ts
@@ -8,6 +8,7 @@ import { compareSemverVersions } from "./semver.ts";
// scripts/install.sh and install.ps1 repeat it; scripts/install.test.ts keeps them in step.
export const CLI_RELEASE_REPOSITORY = "jayleaton/t3code";
export const CLI_RELEASES_PAGE_URL = `https://github.com/${CLI_RELEASE_REPOSITORY}/releases`;
+export const LICENSE_URL = `https://github.com/${CLI_RELEASE_REPOSITORY}/blob/main/LICENSE`;
export const CLI_RELEASE_CHECKSUMS_FILE = "SHA256SUMS";
/** The release's `t3` package manifest, listed in its checksums; read by npmReleaseDatabaseMigration. */
export const CLI_RELEASE_MANIFEST_FILE = "t3-release.json";
diff --git a/packages/shared/src/speech.ts b/packages/shared/src/speech.ts
index c5ed9ab14ea0a..33df73389bbb2 100644
--- a/packages/shared/src/speech.ts
+++ b/packages/shared/src/speech.ts
@@ -7,12 +7,14 @@ import {
} from "@t3tools/contracts";
import * as Schema from "effect/Schema";
+import { APP_NAME } from "./branding.ts";
+
const decodeOptions = Schema.decodeUnknownSync(Schema.fromJsonString(SpeechTranscriptionOptions));
const encodeOptions = Schema.encodeSync(Schema.fromJsonString(SpeechTranscriptionOptions));
export function cloudSpeechDisclosure(provider: CloudSpeechProvider, environment: string) {
return provider === "openrouter"
- ? `After you stop, ${environment} sends the recording to OpenRouter. OpenRouter chooses who runs your model. T3 requests zero data retention; your OpenRouter account may allow safety retention.`
+ ? `After you stop, ${environment} sends the recording to OpenRouter. OpenRouter chooses who runs your model. ${APP_NAME} requests zero data retention; your OpenRouter account may allow safety retention.`
: `After you stop, ${environment} sends your recording and vocabulary hints, including project names, to ${CLOUD_SPEECH_PROVIDER_NAMES[provider]}.`;
}
diff --git a/packages/shared/src/themePalettes.ts b/packages/shared/src/themePalettes.ts
index 19e321c5886c3..2134e2e3ccd9d 100644
--- a/packages/shared/src/themePalettes.ts
+++ b/packages/shared/src/themePalettes.ts
@@ -235,7 +235,7 @@ export const T3_CODE_DARK_THEME_COLORS: ThemeColors = {
export const T3_CHAT_THEME: ThemeDefinition = {
id: "t3-chat",
- label: "T3 Chat",
+ label: "Orchid",
appearance: "light",
colors: {
canvas: "oklch(0.982446 0.010114 325.653)",
diff --git a/packages/ssh/src/tunnel.test.ts b/packages/ssh/src/tunnel.test.ts
index 0d9786c22fc3f..267652e542727 100644
--- a/packages/ssh/src/tunnel.test.ts
+++ b/packages/ssh/src/tunnel.test.ts
@@ -217,7 +217,7 @@ describe("ssh tunnel scripts", () => {
assert.include(result.stderr, "download attempt");
} else {
assert.notInclude(result.stderr, "download attempt");
- assert.include(result.stderr, "has no t3 release archive.");
+ assert.include(result.stderr, "has no Ada release archive.");
}
} finally {
NodeFS.rmSync(root, { recursive: true, force: true });
diff --git a/packages/ssh/src/tunnel.ts b/packages/ssh/src/tunnel.ts
index 8d32e752f5d8a..2f9e13ddd55a7 100644
--- a/packages/ssh/src/tunnel.ts
+++ b/packages/ssh/src/tunnel.ts
@@ -456,11 +456,11 @@ if [ -n "$T3_NODE_SCRIPT_PATH" ]; then
fi
T3_ARCHIVE_VERSION=@@T3_ARCHIVE_VERSION@@
if [ -z "$T3_ARCHIVE_VERSION" ]; then
- printf 'No t3 release version was provided for the remote runtime.\\n' >&2
+ printf 'No ${APP_NAME} release version was provided for the remote runtime.\\n' >&2
exit 1
fi
# Self-contained release archive: no Node, npm, or compiler on the remote.
-# Unpacked into the pinned-runtime layout so \`t3 service install\` reuses it.
+# Unpacked into the pinned-runtime layout so \`ada service install\` reuses it.
T3_RELEASE_BASE_URL=@@T3_RELEASE_BASE_URL@@
T3_RUNTIME_DIR="$HOME/.t3/runtime/versions/$T3_ARCHIVE_VERSION"
t3_runtime_ready() {
@@ -503,7 +503,7 @@ if ! t3_runtime_ready; then
"Darwin arm64") T3_PLATFORM_KEY="darwin-arm64" ;;
"Linux arm64" | "Linux aarch64") T3_PLATFORM_KEY="linux-arm64" ;;
"Linux x86_64" | "Linux amd64") T3_PLATFORM_KEY="linux-x64" ;;
- *) printf 'Remote host %s has no t3 release archive.\\n' "$(uname -s) $(uname -m)" >&2; exit 1 ;;
+ *) printf 'Remote host %s has no ${APP_NAME} release archive.\\n' "$(uname -s) $(uname -m)" >&2; exit 1 ;;
esac
T3_ARCHIVE="t3-$T3_ARCHIVE_VERSION-$T3_PLATFORM_KEY.tar.gz"
T3_STAGING="$(mktemp -d "$HOME/.t3/runtime/versions/.staging-XXXXXX")"
@@ -870,7 +870,7 @@ export class SshInvalidArchiveVersionError extends Schema.TaggedError()(
"AndroidIconRenderError",
{ layer: Schema.String, cause: Schema.Defect() },
) {}
-const wordmarkTransform = (size: number) => {
- const scale = (size * WORDMARK_FRACTION) / TEXT.width;
- const tx = (size - TEXT.width * scale) / 2 - TEXT.x * scale;
- const ty = (size - TEXT.height * scale) / 2 - TEXT.y * scale;
- return `translate(${tx.toFixed(3)} ${ty.toFixed(3)}) scale(${scale.toFixed(4)})`;
-};
-
-const canvasSvg = (size: number, inner: string) =>
- ``;
-
-// Remove the iOS 10pt corner clip; Android's own mask needs full bleed.
-const fullBleed = (svg: string) =>
- svg.replace(//, '');
-
const rasterize = (layer: string, svg: string, width: number, height = width) =>
Effect.tryPromise({
try: () =>
@@ -48,162 +46,70 @@ const rasterize = (layer: string, svg: string, width: number, height = width) =>
catch: (cause) => new AndroidIconRenderError({ layer, cause }),
});
-const composite = (
- layer: string,
- base: Buffer,
- overlays: ReadonlyArray<{ input: Buffer; left?: number; top?: number }>,
-) =>
- Effect.tryPromise({
- try: () =>
- sharp(base)
- .composite([...overlays])
- .png()
- .toBuffer(),
- catch: (cause) => new AndroidIconRenderError({ layer, cause }),
- });
-
-const solidCanvas = (layer: string, size: number, background: string) =>
- Effect.tryPromise({
- try: () =>
- sharp({ create: { width: size, height: size, channels: 4, background } })
- .png()
- .toBuffer(),
- catch: (cause) => new AndroidIconRenderError({ layer, cause }),
- });
-
-const readLayerSource = Effect.fn("androidIcons.readLayerSource")(function* (
- repositoryRoot: string,
- variant: IconVariant,
- file: string,
-) {
- const fs = yield* FileSystem.FileSystem;
- const path = yield* Path.Path;
- return yield* fs.readFileString(
- path.join(repositoryRoot, "assets", variant, "app-icon.icon", "Assets", file),
- );
-});
-
-const renderForeground = Effect.fn("androidIcons.renderForeground")(function* (
- repositoryRoot: string,
- size: number,
-) {
- const text = yield* readLayerSource(repositoryRoot, "prod", "text.svg");
- const paths = text.match(/]*\/>/g) ?? [];
- return yield* rasterize(
- "foreground",
- canvasSvg(size, `${paths.join("")}`),
- size,
- );
-});
-
-const renderDevelopmentBackground = Effect.fn("androidIcons.renderDevelopmentBackground")(
- function* (repositoryRoot: string, size: number) {
- const annotations = yield* readLayerSource(repositoryRoot, "dev", "annotations.svg");
- const defs = annotations.match(/[\s\S]*?<\/defs>/)?.[0] ?? "";
- const body = annotations.replace(/^[\s\S]*?<\/defs>/, "").replace(/<\/svg>\s*$/, "");
- const paper = yield* readLayerSource(repositoryRoot, "dev", "background.svg");
- const background = yield* rasterize("dev-background", fullBleed(paper), size);
- const overlay = yield* rasterize(
- "dev-annotations",
- canvasSvg(size, `${defs}${body}`),
- size,
- );
- return yield* composite("dev-background", background, [{ input: overlay }]);
- },
-);
-
-const renderNightlyBackground = Effect.fn("androidIcons.renderNightlyBackground")(function* (
- repositoryRoot: string,
- size: number,
-) {
- // Match assets/nightly/app-icon.icon/icon.json; omit blur, which Icon Composer ignores and rasterization smears.
- const clouds = [
- { file: "cloud-lower-left.svg", scale: 25, translation: [-309.6375, 268.66077693836917] },
- {
- file: "cloud-upper-right.svg",
- scale: 15,
- translation: [387.9605131881942, -134.30064713259117],
- },
- ] as const;
- const k = size / COMPOSER_CANVAS_PT;
- const overlays = yield* Effect.forEach(clouds, (cloud) =>
- Effect.gen(function* () {
- const width = Math.round(64 * cloud.scale * k);
- const height = Math.round(32 * cloud.scale * k);
- const left = Math.round((COMPOSER_CANVAS_PT / 2 + cloud.translation[0]) * k - width / 2);
- const top = Math.round((COMPOSER_CANVAS_PT / 2 + cloud.translation[1]) * k - height / 2);
- const source = yield* readLayerSource(repositoryRoot, "nightly", cloud.file);
- const png = yield* rasterize(
- cloud.file,
- source.replace(/ filter="url\(#soft\)"/, ""),
- width,
- height,
- );
- const x0 = Math.max(0, left);
- const y0 = Math.max(0, top);
- const x1 = Math.min(size, left + width);
- const y1 = Math.min(size, top + height);
- const clipped = yield* Effect.tryPromise({
- try: () =>
- sharp(png)
- .extract({ left: x0 - left, top: y0 - top, width: x1 - x0, height: y1 - y0 })
- .png()
- .toBuffer(),
- catch: (cause) => new AndroidIconRenderError({ layer: cloud.file, cause }),
- });
- return { input: clipped, left: x0, top: y0 };
- }),
- );
- const sky = yield* readLayerSource(repositoryRoot, "nightly", "background.svg");
- const background = yield* rasterize("nightly-background", fullBleed(sky), size);
- return yield* composite("nightly-background", background, overlays);
-});
-
-const renderBackground = Effect.fn("androidIcons.renderBackground")(function* (
- repositoryRoot: string,
- variant: IconVariant,
- size: number,
-) {
- switch (variant) {
- case "dev":
- return yield* renderDevelopmentBackground(repositoryRoot, size);
- case "nightly":
- return yield* renderNightlyBackground(repositoryRoot, size);
- case "prod":
- return yield* solidCanvas("prod-background", size, PRODUCTION_BACKGROUND_COLOR);
- }
-});
-
-const renderSplashIcon = Effect.fn("androidIcons.renderSplashIcon")(function* (
- repositoryRoot: string,
- variant: IconVariant,
-) {
- const background = yield* renderBackground(repositoryRoot, variant, SPLASH_CANVAS);
- const foreground = yield* renderForeground(repositoryRoot, SPLASH_CANVAS);
- return yield* composite(`${variant}-splash`, background, [{ input: foreground }]);
-});
+const canvas = (layer: string, pip: Pip, options: Parameters[1]) =>
+ rasterize(layer, pipCanvasSvg(pip, options), options.size);
const exportAndroidIcons = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const repositoryRoot = path.resolve(import.meta.dirname, "..");
- const outputs = [
- ["android-icon-foreground.png", yield* renderForeground(repositoryRoot, ADAPTIVE_CANVAS)],
+ const pip = parsePip(yield* fs.readFileString(path.join(repositoryRoot, PIP_SOURCE)));
+ const splashMarkHeight = Math.round((SPLASH_MARK_WIDTH * pip.height) / pip.width);
+
+ const outputs: ReadonlyArray = [
+ [
+ `${OUTPUT_DIRECTORY}/ios-icon-1024.png`,
+ yield* canvas("ios-icon", pip, {
+ size: IOS_CANVAS,
+ fraction: ICON_FRACTION,
+ fill: PIP_COLORS.lavender,
+ background: PIP_COLORS.navy,
+ lift: PIP_ICON_LIFT,
+ }),
+ ],
+ [
+ `${OUTPUT_DIRECTORY}/splash-mark.png`,
+ yield* rasterize(
+ "splash-mark",
+ pipGlyphSvg(pip, PIP_COLORS.lavender),
+ SPLASH_MARK_WIDTH,
+ splashMarkHeight,
+ ),
+ ],
+ [
+ `${OUTPUT_DIRECTORY}/android-icon-foreground.png`,
+ yield* canvas("android-foreground", pip, {
+ size: ADAPTIVE_CANVAS,
+ fraction: ANDROID_FRACTION,
+ fill: PIP_COLORS.lavender,
+ }),
+ ],
[
- "android-icon-background-dev.png",
- yield* renderDevelopmentBackground(repositoryRoot, ADAPTIVE_CANVAS),
+ `${OUTPUT_DIRECTORY}/android-icon-monochrome.png`,
+ yield* canvas("android-monochrome", pip, {
+ size: ADAPTIVE_CANVAS,
+ fraction: ANDROID_FRACTION,
+ fill: PIP_COLORS.white,
+ }),
],
[
- "android-icon-background-nightly.png",
- yield* renderNightlyBackground(repositoryRoot, ADAPTIVE_CANVAS),
+ `${OUTPUT_DIRECTORY}/android-splash-icon.png`,
+ yield* canvas("android-splash", pip, {
+ size: SPLASH_CANVAS,
+ fraction: ANDROID_FRACTION,
+ fill: PIP_COLORS.lavender,
+ background: PIP_COLORS.navy,
+ }),
],
- ["android-splash-icon-dev.png", yield* renderSplashIcon(repositoryRoot, "dev")],
- ["android-splash-icon-nightly.png", yield* renderSplashIcon(repositoryRoot, "nightly")],
- ["android-splash-icon-prod.png", yield* renderSplashIcon(repositoryRoot, "prod")],
- ] as const;
- for (const [name, contents] of outputs) {
- yield* fs.writeFile(path.join(repositoryRoot, OUTPUT_DIRECTORY, name), contents);
- yield* Console.log(`wrote ${OUTPUT_DIRECTORY}/${name}`);
+ // A template image: iOS tints it, so only the shape matters.
+ [WIDGET_MARK, pipGlyphSvg(pip, PIP_COLORS.black)],
+ ];
+ for (const [relativePath, contents] of outputs) {
+ yield* fs.writeFile(
+ path.join(repositoryRoot, relativePath),
+ typeof contents === "string" ? new TextEncoder().encode(contents) : contents,
+ );
+ yield* Console.log(`wrote ${relativePath}`);
}
});
diff --git a/scripts/export-brand-icons.ts b/scripts/export-brand-icons.ts
index 052665b7c2983..a9e2ae6b0b781 100644
--- a/scripts/export-brand-icons.ts
+++ b/scripts/export-brand-icons.ts
@@ -12,9 +12,11 @@ import * as Schema from "effect/Schema";
import * as Stream from "effect/Stream";
import { Command, Flag } from "effect/cli";
import { ChildProcess, ChildProcessSpawner } from "effect/process";
+import sharp from "sharp";
import { BRAND_ASSET_PATHS, DEVELOPMENT_PUBLIC_ICON_OVERRIDES } from "./lib/brand-assets.ts";
import { encodePngIco, readPngDimensions, WINDOWS_ICON_SIZES } from "./lib/icon-export.ts";
+import { parsePip, PIP_COLORS, PIP_SOURCE, pipGlyphSvg } from "./lib/pip.ts";
const DESIGN_GENERATION = 26;
const ICON_COMPOSER_EXECUTABLE_PARTS = [
@@ -255,6 +257,57 @@ const ICON_VARIANTS = [
},
] as const satisfies ReadonlyArray;
+// Each Icon Composer project draws Pip in its own colour over its own backdrop.
+const ICON_COMPOSER_GLYPHS = [
+ { project: BRAND_ASSET_PATHS.productionIconComposerProject, fill: PIP_COLORS.lavender },
+ { project: BRAND_ASSET_PATHS.nightlyIconComposerProject, fill: PIP_COLORS.white },
+ { project: BRAND_ASSET_PATHS.developmentIconComposerProject, fill: PIP_COLORS.white },
+] as const;
+
+// Byte copies of rendered assets. The fork ships the production render as its agents brand.
+const GENERATED_COPIES = [
+ [BRAND_ASSET_PATHS.productionMacIconPng, BRAND_ASSET_PATHS.agentsDesktopIconPng],
+ [BRAND_ASSET_PATHS.productionWindowsIconIco, BRAND_ASSET_PATHS.agentsWindowsIconIco],
+ [BRAND_ASSET_PATHS.productionWebFaviconIco, BRAND_ASSET_PATHS.agentsWebFaviconIco],
+ [BRAND_ASSET_PATHS.productionWebFavicon16Png, BRAND_ASSET_PATHS.agentsWebFavicon16Png],
+ [BRAND_ASSET_PATHS.productionWebFavicon32Png, BRAND_ASSET_PATHS.agentsWebFavicon32Png],
+ [BRAND_ASSET_PATHS.productionWebAppleTouchIconPng, BRAND_ASSET_PATHS.agentsWebAppleTouchIconPng],
+ [BRAND_ASSET_PATHS.productionWebIcon192Png, BRAND_ASSET_PATHS.agentsWebIcon192Png],
+ [BRAND_ASSET_PATHS.productionWebIcon512Png, BRAND_ASSET_PATHS.agentsWebIcon512Png],
+ [BRAND_ASSET_PATHS.productionWebAppleTouchIconPng, "apps/web/public/brand-mark.png"],
+ [BRAND_ASSET_PATHS.productionWebFaviconIco, "apps/marketing/public/favicon.ico"],
+ [BRAND_ASSET_PATHS.productionWebFavicon16Png, "apps/marketing/public/favicon-16x16.png"],
+ [BRAND_ASSET_PATHS.productionWebFavicon32Png, "apps/marketing/public/favicon-32x32.png"],
+ [BRAND_ASSET_PATHS.productionWebAppleTouchIconPng, "apps/marketing/public/apple-touch-icon.png"],
+] as const;
+
+const MARKETING_ICONS = [
+ [BRAND_ASSET_PATHS.productionIosIconPng, "apps/marketing/src/assets/icon.webp"],
+ [BRAND_ASSET_PATHS.nightlyIosIconPng, "apps/marketing/src/assets/icon-nightly.webp"],
+] as const;
+const SOCIAL_CARD = "apps/marketing/src/assets/social-card.webp";
+
+const SOCIAL_CARD_LOCKUP = "assets/agents/pip-lockup-dark.svg";
+
+// Open Graph card at 2x: the approved dark lockup on its own navy. The slogan uses system fonts,
+// like the rest of this macOS-only export.
+const socialCardSvg = (lockup: string) => {
+ const [width, height] = [2400, 1260];
+ const lockupWidth = 2240;
+ const lockupHeight = (lockupWidth * 560) / 1400;
+ const nested = lockup.replace(
+ /