diff --git a/README.md b/README.md
index 1545cac..2719809 100644
--- a/README.md
+++ b/README.md
@@ -243,12 +243,13 @@ Start isolated work on a new branch with its own worktree.
 
 ```
 /work branch:feature/dark-mode description:Implement dark mode toggle
+/work branch:feature/dark-mode      # description defaults to the branch name
 ```
 
-| Parameter     | Description                         |
-| ------------- | ----------------------------------- |
-| `branch`      | Git branch name (will be sanitized) |
-| `description` | Brief description of the work       |
+| Parameter     | Description                                         |
+| ------------- | --------------------------------------------------- |
+| `branch`      | Git branch name (will be sanitized)                 |
+| `description` | Optional. Defaults to the branch name when omitted. |
 
 **Features:**
 
diff --git a/src/__tests__/work.test.ts b/src/__tests__/work.test.ts
new file mode 100644
index 0000000..c39bce2
--- /dev/null
+++ b/src/__tests__/work.test.ts
@@ -0,0 +1,92 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { ChannelType } from 'discord.js';
+
+vi.mock('../services/dataStore.js');
+vi.mock('../services/worktreeManager.js');
+
+import { work } from '../commands/work.js';
+import * as dataStore from '../services/dataStore.js';
+import * as worktreeManager from '../services/worktreeManager.js';
+
+function makeInteraction(branch: string, description: string | null) {
+  const threadSend = vi.fn().mockResolvedValue(undefined);
+  const createdThread = { id: 'thread-1', send: threadSend };
+  const threadsCreate = vi.fn().mockResolvedValue(createdThread);
+
+  const channel = {
+    isThread: () => false,
+    type: ChannelType.GuildText,
+    threads: { create: threadsCreate },
+  };
+
+  const optsMap = new Map<string, string | null>([
+    ['branch', branch],
+    ['description', description],
+  ]);
+
+  return {
+    threadsCreate,
+    threadSend,
+    interaction: {
+      channelId: 'channel-1',
+      user: { id: 'user-1' },
+      channel,
+      options: {
+        getString: (name: string, _required?: boolean) => optsMap.get(name) ?? null,
+      },
+      reply: vi.fn().mockResolvedValue(undefined),
+      deferReply: vi.fn().mockResolvedValue(undefined),
+      editReply: vi.fn().mockResolvedValue(undefined),
+    } as any,
+  };
+}
+
+describe('/work — description fallback', () => {
+  beforeEach(() => {
+    vi.clearAllMocks();
+    vi.mocked(worktreeManager.sanitizeBranchName).mockImplementation((b: string) => b);
+    vi.mocked(worktreeManager.createWorktree).mockResolvedValue('/tmp/worktree');
+    vi.mocked(dataStore.getChannelProjectPath).mockReturnValue('/tmp/project');
+    vi.mocked(dataStore.getWorktreeMappingByBranch).mockReturnValue(undefined);
+    vi.mocked(dataStore.setWorktreeMapping).mockReturnValue(undefined);
+  });
+
+  it('uses branch name as description when description is omitted', async () => {
+    const { interaction, threadsCreate } = makeInteraction('feat-foo', null);
+
+    await work.execute(interaction);
+
+    expect(threadsCreate.mock.calls[0][0].name).toBe('🌳 feat-foo: feat-foo');
+    const mapping = vi.mocked(dataStore.setWorktreeMapping).mock.calls[0][0];
+    expect(mapping.description).toBe('feat-foo');
+  });
+
+  it('falls back to branch name when description is whitespace-only', async () => {
+    const { interaction, threadsCreate } = makeInteraction('feat-bar', '   ');
+
+    await work.execute(interaction);
+
+    expect(threadsCreate.mock.calls[0][0].name).toBe('🌳 feat-bar: feat-bar');
+    const mapping = vi.mocked(dataStore.setWorktreeMapping).mock.calls[0][0];
+    expect(mapping.description).toBe('feat-bar');
+  });
+
+  it('uses provided description verbatim in the thread name', async () => {
+    const { interaction, threadsCreate } = makeInteraction('feat-baz', 'build the thing');
+
+    await work.execute(interaction);
+
+    expect(threadsCreate.mock.calls[0][0].name).toBe('🌳 feat-baz: build the thing');
+    const mapping = vi.mocked(dataStore.setWorktreeMapping).mock.calls[0][0];
+    expect(mapping.description).toBe('build the thing');
+  });
+
+  it('truncates the thread name to 100 characters', async () => {
+    const longDesc = 'x'.repeat(200);
+    const { interaction, threadsCreate } = makeInteraction('feat-long', longDesc);
+
+    await work.execute(interaction);
+
+    expect(threadsCreate.mock.calls[0][0].name.length).toBe(100);
+  });
+});
diff --git a/src/commands/work.ts b/src/commands/work.ts
index a1fce3a..6b5d19f 100644
--- a/src/commands/work.ts
+++ b/src/commands/work.ts
@@ -14,14 +14,15 @@ export const work: Command = {
     )
     .addStringOption(option =>
       option.setName('description')
-        .setDescription('Description of the work')
-        .setRequired(true)
+        .setDescription('Description of the work (defaults to branch name)')
+        .setRequired(false)
     ) as SlashCommandBuilder,
 
   execute: async (interaction: any) => {
     const i = interaction as ChatInputCommandInteraction;
     const branchInput = i.options.getString('branch', true);
-    const description = i.options.getString('description', true);
+    const sanitizedBranch = worktreeManager.sanitizeBranchName(branchInput);
+    const description = i.options.getString('description')?.trim() || sanitizedBranch;
 
     const channel = i.channel;
     if (!channel) {
@@ -54,8 +55,6 @@ export const work: Command = {
       return;
     }
 
-    const sanitizedBranch = worktreeManager.sanitizeBranchName(branchInput);
-
     const existingMapping = dataStore.getWorktreeMappingByBranch(projectPath, sanitizedBranch);
     if (existingMapping) {
       await i.reply({
