Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,13 @@
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
"endOfLine": "lf",
"overrides": [
{
"files": "docs/**/*.mdx",
"options": {
"parser": "mdx"
}
}
]
}
14 changes: 11 additions & 3 deletions docs/agentic-git-identity.md → docs/agentic-git-identity.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ Create a separate GitHub account for your agent:
2. Use a distinctive username (e.g., `yourname-agent`, `yourname-ai`)
3. Use a separate email (GitHub allows plus-addressing: `yourname+ai@example.com`)

<Info>This is optional but recommended. You can also use your main account with a different email/name.</Info>
<Info>
This is optional but recommended. You can also use your main account with a different email/name.
</Info>

## Step 2: Generate Classic GitHub Token

Expand Down Expand Up @@ -57,7 +59,10 @@ Add the Git identity environment variables as [Project Secrets](/project-secrets

These environment variables will be automatically injected when the agent runs Git commands in that project.

<Info>If you need the agent identity outside of mux, you can alternatively set these as global environment variables in your shell configuration (`~/.zshrc`, `~/.bashrc`, etc.)</Info>
<Info>
If you need the agent identity outside of mux, you can alternatively set these as global
environment variables in your shell configuration (`~/.zshrc`, `~/.bashrc`, etc.)
</Info>

## Step 4: Configure GitHub Authentication

Expand Down Expand Up @@ -101,4 +106,7 @@ git config --global credential.helper ""
git config --global --add credential.helper '!gh auth git-credential'
```

<Warning>The "replace all" approach will disable platform keychain helpers and may break Git authentication for non-GitHub remotes (GitLab, Bitbucket, etc.).</Warning>
<Warning>
The "replace all" approach will disable platform keychain helpers and may break Git authentication
for non-GitHub remotes (GitLab, Bitbucket, etc.).
</Warning>
File renamed without changes.
File renamed without changes.
4 changes: 3 additions & 1 deletion docs/context-management.md → docs/context-management.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ Remove oldest 50% of messages.

### OpenAI Responses API Limitation

<Warning>`/truncate` does not work with OpenAI models due to the Responses API architecture:</Warning>
<Warning>
`/truncate` does not work with OpenAI models due to the Responses API architecture:
</Warning>

- OpenAI's Responses API stores conversation state server-side
- Manual message deletion via `/truncate` doesn't affect the server-side state
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
15 changes: 12 additions & 3 deletions docs/install.md → docs/install.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ Download pre-built binaries of `main` from [GitHub Actions](https://github.com/c
- `macos-dmg-arm64` (Apple Silicon)
- **Linux**: AppImage (portable, works on most distros)

<Info>Windows builds are only available from [releases](https://github.com/coder/mux/releases), not from development builds.</Info>
<Info>
Windows builds are only available from [releases](https://github.com/coder/mux/releases), not from
development builds.
</Info>

To download:

Expand Down Expand Up @@ -57,11 +60,17 @@ The app is code-signed and notarized by Apple, so it will open without security
3. Follow the installation prompts
4. Launch Mux from the Start menu or desktop shortcut

<Warning>Windows support is currently in alpha. Please [report any issues](https://github.com/coder/mux/issues) you encounter.</Warning>
<Warning>
Windows support is currently in alpha. Please [report any
issues](https://github.com/coder/mux/issues) you encounter.
</Warning>

### Testing Pre-Release Builds

<Warning>Only builds from the `main` branch are signed and notarized. If you're testing a build from a pull request or other branch, you'll need to bypass macOS Gatekeeper:</Warning>
<Warning>
Only builds from the `main` branch are signed and notarized. If you're testing a build from a pull
request or other branch, you'll need to bypass macOS Gatekeeper:
</Warning>

1. After installing, open Terminal
2. Run: `xattr -cr /Applications/Mux.app`
Expand Down
File renamed without changes.
5 changes: 4 additions & 1 deletion docs/keybinds.md → docs/keybinds.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ description: Complete keyboard shortcut reference for mux

mux is designed to be keyboard-driven for maximum efficiency. All major actions have keyboard shortcuts.

<Info>This document should be kept in sync with `src/utils/ui/keybinds.ts`, which is the source of truth for keybind definitions.</Info>
<Info>
This document should be kept in sync with `src/utils/ui/keybinds.ts`, which is the source of truth
for keybind definitions.
</Info>

## Platform Conventions

Expand Down
22 changes: 22 additions & 0 deletions docs/models.md → docs/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ See also:

mux supports multiple AI providers through its flexible provider architecture.

### First-class models

mux ships with a curated set of first-class models that we keep up to date with the frontier. You can also use any custom model from a supported provider with `/model <provider:model_id>`.

{/* BEGIN KNOWN_MODELS_TABLE */}

| Model | ID | Aliases | Default |
| -------------------- | --------------------------- | ---------------------------------------- | ------- |
| Opus 4.5 | anthropic:claude-opus-4-5 | `opus` | ✓ |
| Sonnet 4.5 | anthropic:claude-sonnet-4-5 | `sonnet` | |
| Haiku 4.5 | anthropic:claude-haiku-4-5 | `haiku` | |
| GPT-5.1 | openai:gpt-5.1 | `gpt-5.1` | |
| GPT-5 Pro | openai:gpt-5-pro | `gpt-5-pro` | |
| GPT-5.1 Codex | openai:gpt-5.1-codex | `codex` | |
| GPT-5.1 Codex Mini | openai:gpt-5.1-codex-mini | `codex-mini` | |
| GPT-5.1 Codex Max | openai:gpt-5.1-codex-max | `codex-max` | |
| Gemini 3 Pro Preview | google:gemini-3-pro-preview | `gemini-3`, `gemini-3-pro` | |
| Grok 4 1 Fast | xai:grok-4-1-fast | `grok`, `grok-4`, `grok-4.1`, `grok-4-1` | |
| Grok Code Fast 1 | xai:grok-code-fast-1 | `grok-code` | |

{/* END KNOWN_MODELS_TABLE */}

### Supported Providers

#### Anthropic (Cloud)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 9 additions & 3 deletions docs/runtime/local.md → docs/runtime/local.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ Local runtime runs the agent directly in your project directory—the same direc

## Caveats

<Warning>**No isolation**: Multiple local workspaces for the same project see and modify the same files. Running them simultaneously can cause conflicts. mux shows a warning when another local workspace is actively streaming.</Warning>

<Warning>**Affects your working copy**: Agent changes happen in your actual project directory.</Warning>
<Warning>
**No isolation**: Multiple local workspaces for the same project see and modify the same files.
Running them simultaneously can cause conflicts. mux shows a warning when another local workspace
is actively streaming.
</Warning>

<Warning>
**Affects your working copy**: Agent changes happen in your actual project directory.
</Warning>

## Filesystem

Expand Down
4 changes: 3 additions & 1 deletion docs/runtime/ssh.md → docs/runtime/ssh.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ Host ovh-1

## Authentication

<Info>As we delegate to `ssh`, this is really an abbreviated reference of how `ssh` authenticates.</Info>
<Info>
As we delegate to `ssh`, this is really an abbreviated reference of how `ssh` authenticates.
</Info>

There are a few practical ways to set up authentication.

Expand Down
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion docs/system-prompt.md → docs/system-prompt.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Even with consistent support at the protocol layer, we have found that different

Here's a snippet from `src/node/services/systemMessage.ts` which is our shared system prompt (minus tools).


{/* BEGIN SYSTEM_PROMPT_DOCS */}

```typescript
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions fmt.mk
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
.PHONY: fmt fmt-check fmt-prettier fmt-prettier-check fmt-shell fmt-shell-check fmt-nix fmt-nix-check fmt-python fmt-python-check fmt-sync-docs fmt-sync-docs-check

# Centralized patterns - single source of truth
PRETTIER_PATTERNS := 'src/**/*.{ts,tsx,json}' 'mobile/**/*.{ts,tsx,json}' 'tests/**/*.ts' 'docs/**/*.md' 'package.json' 'tsconfig*.json' 'README.md'
PRETTIER_PATTERNS := 'src/**/*.{ts,tsx,json}' 'mobile/**/*.{ts,tsx,json}' 'tests/**/*.ts' 'docs/**/*.mdx' 'package.json' 'tsconfig*.json' 'README.md'
SHELL_SCRIPTS := scripts
PYTHON_DIRS := benchmarks

Expand Down Expand Up @@ -94,7 +94,7 @@ else
endif

fmt-sync-docs:
@./scripts/sync_system_prompt_docs.sh
@bun scripts/gen_docs.ts

fmt-sync-docs-check:
@./scripts/sync_system_prompt_docs.sh check
@bun scripts/gen_docs.ts check
185 changes: 185 additions & 0 deletions scripts/gen_docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/usr/bin/env bun
/**
* Generate documentation snippets from source files.
*
* Usage:
* bun scripts/gen_docs.ts # write mode (update docs)
* bun scripts/gen_docs.ts check # check mode (verify docs are up-to-date)
*
* This script synchronizes:
* - docs/system-prompt.mdx: snippet from src/node/services/systemMessage.ts
* - docs/models.mdx: table from src/common/constants/knownModels.ts
*/

import * as fs from "fs";
import * as path from "path";
import { KNOWN_MODELS, DEFAULT_MODEL } from "../src/common/constants/knownModels";
import { formatModelDisplayName } from "../src/common/utils/ai/modelDisplay";

const MODE = process.argv[2] === "check" ? "check" : "write";
const DOCS_DIR = path.join(import.meta.dir, "..", "docs");

// ---------------------------------------------------------------------------
// Marker helpers
// ---------------------------------------------------------------------------

function injectBetweenMarkers(content: string, markerName: string, block: string): string {
const beginMarker = `{/* BEGIN ${markerName} */}`;
const endMarker = `{/* END ${markerName} */}`;

const beginIdx = content.indexOf(beginMarker);
const endIdx = content.indexOf(endMarker);

if (beginIdx === -1 || endIdx === -1) {
throw new Error(`Missing markers for ${markerName}`);
}

const before = content.slice(0, beginIdx + beginMarker.length);
const after = content.slice(endIdx);

return `${before}\n\n${block}\n\n${after}`;
}

// ---------------------------------------------------------------------------
// Generic sync helper
// ---------------------------------------------------------------------------

interface SyncDocOptions {
docsFile: string;
sourceLabel: string;
markerName: string;
generateBlock: () => string;
}

async function syncDoc(options: SyncDocOptions): Promise<boolean> {
const { docsFile, sourceLabel, markerName, generateBlock } = options;
const docsPath = path.join(DOCS_DIR, docsFile);

const currentContent = fs.readFileSync(docsPath, "utf-8");
const block = generateBlock();
const newContent = injectBetweenMarkers(currentContent, markerName, block);

if (currentContent === newContent) {
console.log(`✓ ${docsFile} is up-to-date with ${sourceLabel}`);
return true;
}

if (MODE === "check") {
console.error(`✗ ${docsFile} is out of sync with ${sourceLabel}`);
console.error(` Run 'make fmt' to regenerate.`);
return false;
}

fs.writeFileSync(docsPath, newContent, "utf-8");
console.log(`✓ Updated ${docsFile} from ${sourceLabel}`);
return true;
}

// ---------------------------------------------------------------------------
// System prompt sync
// ---------------------------------------------------------------------------

function generateSystemPromptBlock(): string {
const systemMessagePath = path.join(
import.meta.dir,
"..",
"src",
"node",
"services",
"systemMessage.ts"
);
const source = fs.readFileSync(systemMessagePath, "utf-8");

const regionStart = "// #region SYSTEM_PROMPT_DOCS";
const regionEnd = "// #endregion SYSTEM_PROMPT_DOCS";

const startIdx = source.indexOf(regionStart);
const endIdx = source.indexOf(regionEnd);

if (startIdx === -1 || endIdx === -1) {
throw new Error("Could not find SYSTEM_PROMPT_DOCS region in systemMessage.ts");
}

const snippet = source.slice(startIdx + regionStart.length, endIdx).trim();
return "```typescript\n" + snippet + "\n```";
}

async function syncSystemPrompt(): Promise<boolean> {
return syncDoc({
docsFile: "system-prompt.mdx",
sourceLabel: "src/node/services/systemMessage.ts",
markerName: "SYSTEM_PROMPT_DOCS",
generateBlock: generateSystemPromptBlock,
});
}

// ---------------------------------------------------------------------------
// Known models table sync
// ---------------------------------------------------------------------------

function generateKnownModelsTable(): string {
const rows: Array<{ name: string; id: string; aliases: string; isDefault: boolean }> = [];

for (const model of Object.values(KNOWN_MODELS)) {
rows.push({
name: formatModelDisplayName(model.providerModelId),
id: model.id,
aliases: (model.aliases ?? []).map((a) => `\`${a}\``).join(", ") || "—",
isDefault: model.id === DEFAULT_MODEL,
});
}

// Calculate column widths
const headers = ["Model", "ID", "Aliases", "Default"];
const widths = headers.map((h, i) => {
const colValues = rows.map((r) => {
if (i === 0) return r.name;
if (i === 1) return r.id;
if (i === 2) return r.aliases;
return r.isDefault ? "✓" : "";
});
return Math.max(h.length, ...colValues.map((v) => v.length));
});

const pad = (s: string, w: number) => s + " ".repeat(w - s.length);

const headerRow = `| ${headers.map((h, i) => pad(h, widths[i])).join(" | ")} |`;
const sepRow = `| ${widths.map((w) => "-".repeat(w)).join(" | ")} |`;
const dataRows = rows.map((r) => {
const cells = [
pad(r.name, widths[0]),
pad(r.id, widths[1]),
pad(r.aliases, widths[2]),
pad(r.isDefault ? "✓" : "", widths[3]),
];
return `| ${cells.join(" | ")} |`;
});

return [headerRow, sepRow, ...dataRows].join("\n");
}

async function syncKnownModels(): Promise<boolean> {
return syncDoc({
docsFile: "models.mdx",
sourceLabel: "src/common/constants/knownModels.ts",
markerName: "KNOWN_MODELS_TABLE",
generateBlock: generateKnownModelsTable,
});
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

async function main(): Promise<void> {
const results = await Promise.all([syncSystemPrompt(), syncKnownModels()]);

if (results.some((r) => !r)) {
process.exit(1);
}
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
Loading