-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Motivation
When a user runs jack vibe "build a chat app with rooms", they want to watch an AI agent build it and jump in when needed. Today the flow is fragmented:
jack viberuns the agent in one-shot mode (claude -pwith--permission-mode acceptEdits) — the user can't interactjack new --openlaunches the agent interactively but with a generic prompt ("say hi and offer to help build") — the user's intent is lost- There's no flow that combines both: create project → launch agent interactively with the user's intent → user watches and takes over
This matters more now that jack creates projects in a central location (~/.jack/projects/), because the user doesn't need to think about where to put things. The ideal UX is:
jack vibe "real-time chat with persistent rooms"
→ project created at ~/.jack/projects/chat-rooms/
→ deployed to https://user-chat-rooms.runjack.xyz
→ Claude Code opens interactively with the intent as its first prompt
→ user watches it work, jumps in whenever they want
Current State
What exists
jack vibe "<intent>" (index.ts) — alias for jack new with intent: args[0]
- Calls
newProject()which creates the project from a template - If intent is provided, runs
runAgentOneShot()(non-interactiveclaude -p) to customize the project - After one-shot completes, the session ends — user has to manually open the project
jack new --open (new.ts:112-143) — launches agent interactively after project creation
- Calls
launchAgent()which spawnsclaude <prompt>withstdio: "inherit"(interactive) - The initial prompt is built by
buildInitialPrompt()— only includes project name and URL - Does NOT include the user's intent phrase
- User's intent is lost between the one-shot customization and the interactive launch
buildInitialPrompt() (agents.ts:434-439):
function buildInitialPrompt(context: AgentLaunchContext): string | null {
if (!context.url) return null;
return `Project "${context.projectName}" is live at ${context.url}\n\nRead CLAUDE.md and AGENTS.md for project context, then say hi and offer to help build.`;
}- Generic "say hi" prompt — doesn't tell the agent what to build
- Only fires if URL exists
AgentLaunchContexthas nointentfield
runAgentOneShot() (agents.ts:640-915):
- Runs
claude -p "<prompt>" --permission-mode acceptEdits --output-format stream-json - Non-interactive — user sees status updates but can't intervene
- Good for automated customization, wrong for "watch and take over" UX
launchAgent() (agents.ts:472-506):
- Spawns
claude <prompt>withstdio: "inherit"— fully interactive - User can take over immediately
- This is the right primitive for the desired UX
Key insight: claude <prompt> (no -p flag) is interactive
claude -p = pipe mode (non-interactive, for automation)
claude <prompt> = starts interactive session with initial prompt (user can take over)
Jack already uses the interactive form in launchAgent(). The gap is wiring the intent through.
Proposed Changes
1. Add intent to AgentLaunchContext
export interface AgentLaunchContext {
projectName?: string;
url?: string | null;
intent?: string; // User's intent phrase from `jack vibe`
}2. Update buildInitialPrompt() to include intent
function buildInitialPrompt(context: AgentLaunchContext): string | null {
const parts: string[] = [];
if (context.url) {
parts.push(`Project "${context.projectName}" is live at ${context.url}`);
}
if (context.intent) {
parts.push(`Intent: "${context.intent}"`);
parts.push('Read CLAUDE.md and AGENTS.md for project context, then implement the intent above.');
parts.push('The project is already deployed — use `jack ship` to redeploy after changes.');
} else {
parts.push('Read CLAUDE.md and AGENTS.md for project context, then say hi and offer to help build.');
}
return parts.length > 0 ? parts.join('\n\n') : null;
}3. Change jack vibe default behavior
When intent is provided:
- Create project from best-match template (existing)
- Deploy (existing)
- Instead of one-shot → launch agent interactively with the intent as the initial prompt
- User sees Claude Code start working, can take over any time
The one-shot path could remain available via a flag (--headless or --auto) for CI/scripting use cases.
4. Wire intent through jack new --open
Pass intent to launchAgent():
const launchResult = await launchAgent(preferred.launch, result.targetDir, {
projectName: result.projectName,
url: result.workerUrl,
intent: options.intent, // from jack vibe's intent phrase
});Files to Change
| File | Change |
|---|---|
apps/cli/src/lib/agents.ts |
Add intent to AgentLaunchContext, update buildInitialPrompt() |
apps/cli/src/commands/new.ts |
Pass intent to launchAgent() when --open or via jack vibe |
apps/cli/src/index.ts |
Wire jack vibe to use interactive launch instead of one-shot |
Non-Goals
- Changing one-shot mode (
runAgentOneShot) — it's useful for headless/CI - Adding new agent integrations — use existing
launchAgent()primitive - Changing project creation location —
~/.jack/projects/is already the default