Skip to content

Commit a7db9ed

Browse files
committed
feat(slash): add guide mode
1 parent a1ead04 commit a7db9ed

9 files changed

Lines changed: 186 additions & 24 deletions

File tree

core/config/profile/doLoadConfig.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { getControlPlaneEnv } from "../../control-plane/env.js";
2828
import { PolicySingleton } from "../../control-plane/PolicySingleton";
2929
import { TeamAnalytics } from "../../control-plane/TeamAnalytics.js";
3030
import ContinueProxy from "../../llm/llms/stubs/ContinueProxy";
31+
import { guideSlashCommand } from "../../promptFiles/guidePrompt";
3132
import { initSlashCommand } from "../../promptFiles/initPrompt";
3233
import { getConfigDependentToolDefinitions } from "../../tools";
3334
import { encodeMCPToolUri } from "../../tools/callTool";
@@ -189,6 +190,7 @@ export default async function doLoadConfig(options: {
189190
}
190191

191192
newConfig.slashCommands.push(initSlashCommand);
193+
newConfig.slashCommands.push(guideSlashCommand);
192194

193195
const proxyContextProvider = newConfig.contextProviders?.find(
194196
(cp) => cp.description.title === "continue-proxy",

core/config/profile/doLoadConfig.vitest.ts

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ vi.mock("../../control-plane/TeamAnalytics", () => ({
9595
vi.mock("../../promptFiles/initPrompt", () => ({
9696
initSlashCommand: { name: "init", description: "init" },
9797
}));
98+
vi.mock("../../promptFiles/guidePrompt", () => ({
99+
guideSlashCommand: { name: "guide", description: "guide" },
100+
}));
98101

99102
// Mock fs.existsSync to simulate missing file on disk
100103
vi.mock("fs", async (importOriginal) => {
@@ -133,26 +136,29 @@ const mockControlPlaneClient = {
133136

134137
const mockLlmLogger = {} as any;
135138

139+
function createPackageIdentifier(withContent = true): PackageIdentifier {
140+
return {
141+
uriType: "file",
142+
fileUri: "vscode-remote://wsl+Ubuntu/home/user/.continue/agents/test.yaml",
143+
...(withContent
144+
? { content: "name: Test\nversion: 1.0.0\nschema: v1\n" }
145+
: {}),
146+
};
147+
}
148+
136149
describe("doLoadConfig pre-read content bypass", () => {
137150
it("should use YAML loading when packageIdentifier has pre-read content, even if file does not exist on disk", async () => {
138151
mockLoadYaml.mockClear();
139152
mockLoadJson.mockClear();
140153

141-
const packageIdentifier: PackageIdentifier = {
142-
uriType: "file",
143-
fileUri:
144-
"vscode-remote://wsl+Ubuntu/home/user/.continue/agents/test.yaml",
145-
content: "name: Test\nversion: 1.0.0\nschema: v1\n",
146-
};
147-
148154
await doLoadConfig({
149155
ide: mockIde,
150156
controlPlaneClient: mockControlPlaneClient,
151157
llmLogger: mockLlmLogger,
152158
profileId: "test-profile",
153-
overrideConfigYamlByPath: packageIdentifier.fileUri,
159+
overrideConfigYamlByPath: createPackageIdentifier(true).fileUri,
154160
orgScopeId: null,
155-
packageIdentifier,
161+
packageIdentifier: createPackageIdentifier(true),
156162
});
157163

158164
expect(mockLoadYaml).toHaveBeenCalled();
@@ -163,23 +169,33 @@ describe("doLoadConfig pre-read content bypass", () => {
163169
mockLoadYaml.mockClear();
164170
mockLoadJson.mockClear();
165171

166-
const packageIdentifier: PackageIdentifier = {
167-
uriType: "file",
168-
fileUri:
169-
"vscode-remote://wsl+Ubuntu/home/user/.continue/agents/test.yaml",
170-
};
171-
172172
await doLoadConfig({
173173
ide: mockIde,
174174
controlPlaneClient: mockControlPlaneClient,
175175
llmLogger: mockLlmLogger,
176176
profileId: "test-profile",
177-
overrideConfigYamlByPath: packageIdentifier.fileUri,
177+
overrideConfigYamlByPath: createPackageIdentifier(false).fileUri,
178178
orgScopeId: null,
179-
packageIdentifier,
179+
packageIdentifier: createPackageIdentifier(false),
180180
});
181181

182182
expect(mockLoadYaml).not.toHaveBeenCalled();
183183
expect(mockLoadJson).toHaveBeenCalled();
184184
});
185+
186+
it("should always include built-in init and guide slash commands", async () => {
187+
const result = await doLoadConfig({
188+
ide: mockIde,
189+
controlPlaneClient: mockControlPlaneClient,
190+
llmLogger: mockLlmLogger,
191+
profileId: "test-profile",
192+
overrideConfigYamlByPath: createPackageIdentifier(true).fileUri,
193+
orgScopeId: null,
194+
packageIdentifier: createPackageIdentifier(true),
195+
});
196+
197+
const commandNames = result.config?.slashCommands.map((cmd) => cmd.name);
198+
expect(commandNames).toContain("init");
199+
expect(commandNames).toContain("guide");
200+
});
185201
});

core/promptFiles/guidePrompt.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { SlashCommandWithSource } from "..";
2+
3+
export const GUIDE_PROMPT_CONTENT = `
4+
You are Continue Guide Mode, an interactive mentor for developers who need help turning a rough idea into a concrete implementation plan.
5+
6+
Your job is not to jump straight into coding. First, help the user clarify what they are trying to build, then turn that into a strong implementation brief they can use with Continue.
7+
8+
## Goals
9+
- Help beginners describe their project clearly.
10+
- Ask discovery questions that improve the next coding step.
11+
- Teach the user what information helps AI produce better results.
12+
- End with a concrete, structured specification and a suggested next prompt.
13+
14+
## How to behave
15+
- Be encouraging, practical, and concise.
16+
- Ask only for information that materially improves the plan.
17+
- Prefer plain language over jargon.
18+
- If the user already answered some questions, do not ask them again.
19+
- If the user gives a vague idea, ask targeted follow-up questions.
20+
- Ask at most 2 questions per response so the interaction stays lightweight.
21+
22+
## Discovery Areas
23+
Collect enough detail to cover these five areas:
24+
1. What they want to build.
25+
2. Who it is for.
26+
3. What problem it solves.
27+
4. Their experience level.
28+
5. Requirements, constraints, or preferred technologies.
29+
30+
## Response strategy
31+
- If key information is missing, ask the next most important question or two.
32+
- Once you have enough information, stop asking questions and produce a structured specification.
33+
- If the user asks for direct help before the discovery is complete, give a short answer and then continue the discovery flow.
34+
35+
## When you have enough information
36+
Produce these sections in order:
37+
1. **Project Summary**: one short paragraph.
38+
2. **Structured Specification**: clear bullets for users, problem, features, constraints, and technical preferences.
39+
3. **Implementation Plan**: 3-6 concrete build steps.
40+
4. **Starter Prompt**: a polished prompt the user can paste into Continue to begin implementation.
41+
5. **What To Clarify Next**: optional, only if meaningful gaps remain.
42+
43+
## If the user has not provided any project idea yet
44+
Start by asking: "What are you trying to build? Describe your idea in your own words."
45+
`.trim();
46+
47+
export const guideSlashCommand: SlashCommandWithSource = {
48+
name: "guide",
49+
description: "Turn a rough idea into a structured build plan",
50+
source: "built-in",
51+
prompt: GUIDE_PROMPT_CONTENT,
52+
};

docs/guides/cli.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ sidebarTitle: "Continue CLI (cn)"
44
description: "Learn how to use Continue's command-line interface for context engineering, automated coding tasks, and headless development workflows with customizable models, rules, and tools"
55
---
66

7-
import { OSAutoDetect } from '/snippets/OSAutoDetect.jsx'
8-
import CLIInstall from '/snippets/cli-install.mdx'
7+
import { OSAutoDetect } from "/snippets/OSAutoDetect.jsx";
8+
import CLIInstall from "/snippets/cli-install.mdx";
99

1010
<OSAutoDetect />
1111

@@ -39,7 +39,7 @@ Out of the box, `cn` comes with tools that let it understand your codebase, edit
3939
- Write a new feature
4040
- And a lot more
4141

42-
Use '@' to give it file context, or '/' to run slash commands.
42+
Use '@' to give it file context, or '/' to run slash commands. For example, `/guide build a habit tracker for families` will help turn a rough idea into a clearer implementation brief before you start coding.
4343

4444
If you want to resume a previous conversation, run `cn --resume`.
4545

docs/reference/json-reference.mdx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,25 @@ config.json
399399
}
400400
```
401401

402+
### `/guide`
403+
404+
The guide slash command helps a user turn a rough idea into a more actionable build plan. It asks discovery questions, clarifies the audience and constraints, and then produces a structured specification plus a starter prompt for implementation.
405+
406+
config.json
407+
408+
```json
409+
{
410+
"slashCommands": [
411+
{
412+
"name": "guide",
413+
"description": "Turn a rough idea into a structured build plan"
414+
}
415+
]
416+
}
417+
```
418+
419+
Example: `/guide build a portfolio site for junior developers`
420+
402421
Example:
403422

404423
config.json
@@ -480,7 +499,6 @@ Several experimental config parameters are available, as described below:
480499
- `defaultContext`: Defines the default context for the LLM. Uses the same format as `contextProviders` but includes an additional `query` property to specify custom query parameters.=
481500

482501
- `modelRoles`:
483-
484502
- `inlineEdit`: Model title for inline edits.
485503
- `applyCodeBlock`: Model title for applying code blocks.
486504
- `repoMapFileSelection`: Model title for repo map selections.
@@ -521,18 +539,15 @@ Some deprecated `config.json` settings are no longer stored in config and have b
521539
- `disableSessionTitles`/`ui.getChatTitles`: This value will be migrated to the safest merged value (`true` if either are `true`). `getChatTitles` takes precedence if set to false
522540

523541
- `tabAutocompleteOptions`
524-
525542
- `useCache`: This value will override during migration.
526543
- `disableInFiles`: This value will be migrated to the safest merged value (arrays of file matches merged/deduplicated)
527544
- `multilineCompletions`: This value will override during migration.
528545

529546
- `experimental`
530-
531547
- `useChromiumForDocsCrawling`: This value will override during migration.
532548
- `readResponseTTS`: This value will override during migration.
533549

534550
- `ui` - all will override during migration
535-
536551
- `codeBlockToolbarPosition`
537552
- `fontSize`
538553
- `codeWrap`

extensions/cli/src/commands/commands.integration.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ describe("Slash Commands Integration", () => {
2828
expect(commandNames).toContain("login");
2929
expect(commandNames).toContain("logout");
3030
expect(commandNames).toContain("whoami");
31+
expect(commandNames).toContain("guide");
3132

3233
expect(commandNames).toContain("model");
3334
expect(commandNames).toContain("config");
@@ -50,6 +51,7 @@ describe("Slash Commands Integration", () => {
5051
"login",
5152
"logout",
5253
"whoami",
54+
"guide",
5355
"model",
5456
"config",
5557
].includes(cmd.name),

extensions/cli/src/commands/commands.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ export const SYSTEM_SLASH_COMMANDS: SystemCommand[] = [
8181
description: "Create an AGENTS.md file",
8282
category: "system",
8383
},
84+
{
85+
name: "guide",
86+
description: "Turn a rough idea into a structured build plan",
87+
category: "system",
88+
},
8489
{
8590
name: "compact",
8691
description: "Summarize chat history into a compact form",

extensions/cli/src/slashCommands.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,20 @@ describe("slashCommands", () => {
136136
expect(result?.exit).toBeUndefined();
137137
});
138138

139+
it("should handle /guide command", async () => {
140+
const result = await handleSlashCommands(
141+
"/guide Build a portfolio site for junior developers",
142+
mockAssistant,
143+
);
144+
145+
expect(result).toBeDefined();
146+
expect(result?.newInput).toContain("Continue Guide Mode");
147+
expect(result?.newInput).toContain(
148+
"Build a portfolio site for junior developers",
149+
);
150+
expect(result?.output).toBeUndefined();
151+
});
152+
139153
it("should handle /info command when not authenticated", async () => {
140154
const { isAuthenticated } = await import("./auth/workos.js");
141155
const { services } = await import("./services/index.js");

extensions/cli/src/slashCommands.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,50 @@ import {
2525
loadMarkdownSkills,
2626
} from "./util/loadMarkdownSkills.js";
2727

28+
const GUIDE_PROMPT = `
29+
You are Continue Guide Mode, an interactive mentor for developers who need help turning a rough idea into a concrete implementation plan.
30+
31+
Your job is not to jump straight into coding. First, help the user clarify what they are trying to build, then turn that into a strong implementation brief they can use with Continue.
32+
33+
## Goals
34+
- Help beginners describe their project clearly.
35+
- Ask discovery questions that improve the next coding step.
36+
- Teach the user what information helps AI produce better results.
37+
- End with a concrete, structured specification and a suggested next prompt.
38+
39+
## How to behave
40+
- Be encouraging, practical, and concise.
41+
- Ask only for information that materially improves the plan.
42+
- Prefer plain language over jargon.
43+
- If the user already answered some questions, do not ask them again.
44+
- If the user gives a vague idea, ask targeted follow-up questions.
45+
- Ask at most 2 questions per response so the interaction stays lightweight.
46+
47+
## Discovery Areas
48+
Collect enough detail to cover these five areas:
49+
1. What they want to build.
50+
2. Who it is for.
51+
3. What problem it solves.
52+
4. Their experience level.
53+
5. Requirements, constraints, or preferred technologies.
54+
55+
## Response strategy
56+
- If key information is missing, ask the next most important question or two.
57+
- Once you have enough information, stop asking questions and produce a structured specification.
58+
- If the user asks for direct help before the discovery is complete, give a short answer and then continue the discovery flow.
59+
60+
## When you have enough information
61+
Produce these sections in order:
62+
1. **Project Summary**: one short paragraph.
63+
2. **Structured Specification**: clear bullets for users, problem, features, constraints, and technical preferences.
64+
3. **Implementation Plan**: 3-6 concrete build steps.
65+
4. **Starter Prompt**: a polished prompt the user can paste into Continue to begin implementation.
66+
5. **What To Clarify Next**: optional, only if meaningful gaps remain.
67+
68+
## If the user has not provided any project idea yet
69+
Start by asking: "What are you trying to build? Describe your idea in your own words."
70+
`.trim();
71+
2872
type CommandHandler = (
2973
args: string[],
3074
assistant: AssistantConfig,
@@ -63,6 +107,17 @@ async function handleHelp(_args: string[], _assistant: AssistantConfig) {
63107
return { output: helpMessage };
64108
}
65109

110+
async function handleGuide(args: string[]): Promise<SlashCommandResult> {
111+
const idea = args.join(" ").trim();
112+
return {
113+
newInput: idea
114+
? `${GUIDE_PROMPT}
115+
116+
${idea}`
117+
: GUIDE_PROMPT,
118+
};
119+
}
120+
66121
async function handleLogin() {
67122
try {
68123
const newAuthState = await services.auth.login();
@@ -361,6 +416,7 @@ const commandHandlers: Record<string, CommandHandler> = {
361416
init: (args, assistant) => {
362417
return handleInit(args, assistant);
363418
},
419+
guide: (args) => handleGuide(args),
364420
update: () => {
365421
return { openUpdateSelector: true };
366422
},

0 commit comments

Comments
 (0)