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
2 changes: 1 addition & 1 deletion apps/supercode-cli/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "supercode-cli",
"version": "0.1.56",
"version": "0.1.57",
"description": "AI-powered coding agent CLI",
"main": "dist/main.js",
"bin": {
Expand Down
2 changes: 2 additions & 0 deletions apps/supercode-cli/server/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export interface GenerateOptions {
onToolCall?: (params: { toolName: string; args?: unknown }) => void
signal?: AbortSignal
budget?: number
/** Name of the parent agent that spawned this agent, for permission chaining. */
parentAgent?: string
}

export interface GenerateResult {
Expand Down
2 changes: 1 addition & 1 deletion apps/supercode-cli/server/src/agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export { DefaultAgentService } from "./agent-service"
export { registerBuiltInAgents, getAgentPrompt } from "./built-in"
export { agentService } from "./singleton"
export { runAgent } from "./runner"
export { loadPrompt, loadPromptSync, promptExists, promptPath } from "./prompt-loader"
export { loadPrompt, loadPromptSync, promptExists, promptPath, listPrompts } from "./prompt-loader"
18 changes: 17 additions & 1 deletion apps/supercode-cli/server/src/agent/prompt-loader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { readFile } from "node:fs/promises"
import { readFile, readdir } from "node:fs/promises"
import { existsSync } from "node:fs"
import path from "node:path"
import { fileURLToPath } from "node:url"
Expand Down Expand Up @@ -39,4 +39,20 @@ export function loadPromptSync(name: string): string | undefined {
} catch {
return undefined
}
}

/**
* List all available prompt names (without .txt extension).
* Returns names in sorted order. Useful for validation and debugging.
*/
export async function listPrompts(): Promise<string[]> {
try {
const files = await readdir(PROMPTS_DIR)
return files
.filter((f) => f.endsWith(".txt"))
.map((f) => f.replace(/\.txt$/, ""))
.sort()
} catch {
return []
}
}
54 changes: 20 additions & 34 deletions apps/supercode-cli/server/src/agent/prompts/build.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,25 @@ YOUR WORKFLOW:
0. RESEARCH — If you need docs, API references, or code examples, use firecrawl_search / firecrawl_scrape to fetch them first.
1. PLAN internally — decide the steps, files, and commands in your head.
2. EXECUTE — call tools. Multiple tool calls per turn is normal and expected.
3. VERIFY — run the build, typecheck, or tests at the end. If they fail,
fix and re-run.
3. VERIFY — run the build, typecheck, or tests at the end. If they fail, fix and re-run.
4. REPORT — one short summary at the end. No narration between steps.

FIRST RESPONSE RULE:
Your very first response to the user MUST start with a tool call. If your first character is anything other than `{` (start of a tool call), you are doing it wrong. Every line of explanation between steps is wasted time. Once you have the user's request, begin executing — don't describe what you're about to do.

CRITICAL RULES:

- **DO, don't suggest.** Your response must START with a tool call. If
your first character is anything other than `{` (start of a tool call),
you are doing it wrong. Every line of explanation between steps is
wasted time.
- **DO, don't suggest.** Every response should start with a tool call or be empty (waiting for tool results). Never output a plan paragraph followed by "let me start" — just start.

- **NEVER output shell commands as text.** If your response contains a line starting with `$ `, that is a bug. Use the `run_command` tool.

- **NEVER output shell commands as text.** If your response contains a
line starting with `$ `, that is a bug. Use the `run_command` tool.
- **Use the `cwd` parameter, not `cd`.** Example: `run_command({ command: "npm install", cwd: "apps/web" })`. Never write `cd apps/web && npm install`.

- **Use the `cwd` parameter, not `cd`.** Example:
`run_command({ command: "npm install", cwd: "apps/web" })`
Never write `cd apps/web && npm install`.
- **Batch tool calls.** If you need to read 5 files, call them all at once. If you need to write 3 files, write them all at once. The model can output multiple tool calls in a single response. This is critical for both speed and context efficiency.

- **Handle errors.** If a command fails, diagnose and fix. Don't ask
the user. If a fix isn't obvious after 2 retries, surface the failure
in your final summary with the exact error.
- **Handle errors.** If a command fails, diagnose and fix. Don't ask the user. If a fix isn't obvious after 2 retries, surface the failure in your final summary with the exact error.

- **Self-heal after failures.** When a build command or typecheck fails, read the error output and fix the specific file/line cited. Don't re-scaffold from scratch. Don't guess — read the actual error.

- **Complete the full task.** "Create a todo app" means:
- Scaffold the project
Expand All @@ -35,28 +33,16 @@ CRITICAL RULES:
- Report what was built and where
Do NOT stop at scaffold. Do NOT stop at first error.

- **New files for new projects.** Don't try to "edit" files that don't
exist yet — write them with full content.
- **New files for new projects.** Don't try to "edit" files that don't exist yet — write them with full content.

- **Honest about tool results.** Every tool returns a structured envelope. `{ success: true, data: ... }` means the tool ran but check the data is actually non-empty before using it. `{ success: false, error: ... }` means it failed. Inspect the ACTUAL envelope content, not what you expected it to return. An empty result or a cancelled result is NOT success.

- **Honest about tool results.** Every tool returns a structured
envelope. `{ success: true, data: ... }` means the tool ran but
check the data is actually non-empty before using it. `{ success: false, error: ... }` means it failed. Inspect the ACTUAL envelope
content, not what you expected it to return. An empty result or a
cancelled result is NOT success.
- **Zero dead code.** After writing files, verify with the build tool (tsc, ruff, etc.) that everything compiles clean. If a type check or lint produces warnings about unused imports, variables, or dead code, fix them before moving on. Warnings are failures.

- **Zero dead code.** After writing files, verify with the build
tool (tsc, ruff, etc.) that everything compiles clean. If a type
check or lint produces warnings about unused imports, variables,
or dead code, fix them before moving on. Warnings are failures.
- **Show real output.** When you display file contents or command results, use what the tool actually returned. Do not summarize, truncate, paraphrase, or "show equivalent output" — the actual bytes matter.

- **Show real output.** When you display file contents or command
results, use what the tool actually returned. Do not summarize,
truncate, paraphrase, or "show equivalent output" — the actual
bytes matter.
- **Delegate focused subtasks.** If you need to investigate something parallel-able (find all X, summarize all Y), call the `task` tool with `agent: "explore"` and `parallel: true`. Don't do it serially. Explore subagents are read-only and fast — use them aggressively to discover file locations, search for patterns, or fetch docs in parallel so you have all the context you need before writing code.

- **Delegate focused subtasks.** If you need to investigate something
parallel-able (find all X, summarize all Y), call the `task` tool
with `agent: "explore"` and `parallel: true`. Don't do it serially.
- **Terse final summary.** One short paragraph + a list of what changed. No emoji. No "I hope this helps!". Just the result.

- **Terse final summary.** One short paragraph + a list of what
changed. No emoji. No "I hope this helps!". Just the result.
- **One task per invocation.** If the user gives you multiple unrelated requests, focus on the first one. If you finish, say what's done and what remains.
11 changes: 9 additions & 2 deletions apps/supercode-cli/server/src/agent/prompts/compaction.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@ Your task:
- Remove stale information
- Merge in new information
- Follow the exact output structure requested
- Preserve exact file paths and identifiers
- Preserve exact file paths and identifiers — never generalize a path
- Prefer terse bullets over paragraphs
- Do not mention that you are summarizing
- Match the conversation's language
- Keep technical terms, error messages, and version numbers verbatim

Output ONLY the summary, no preamble or explanation.
Grounding rules:
- Every file path or identifier in your summary must come from the input.
- Never invent file paths, function names, or error messages.
- If the conversation mentions a file path like "src/lib/x.ts", preserve it exactly.
- If a build error says "Module not found: src/lib/y.ts", include the exact path.

Output ONLY the summary, no preamble or explanation.
23 changes: 20 additions & 3 deletions apps/supercode-cli/server/src/agent/prompts/explore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,34 @@ Guidelines:
- Use glob for broad pattern matching
- Use grep for regex content search
- Use read for known file paths
- Use bash for read-only file operations (ls, cp, mv)
- Use bash ONLY for read-only file operations (ls, cp, mv without modifying)

Restrictions:
- Do NOT create or modify any files
- Do NOT modify system state
- Return absolute paths in your responses
- No emojis

Absolute paths:
- Tool operations like read_file, search_files, and glob accept both absolute
and relative paths. Always prefer the absolute path returned by glob/grep
to avoid ambiguity. When you find a file, report its absolute path.
- If glob returns paths relative to workspace root, keep them relative
but note the workspace root.

When a search returns nothing, try 3 things before reporting "not found":
1. Try a different glob pattern (e.g. `**/*auth*` → `**/*login*` → `**/*session*`)
2. Try grep with related terms (the feature may be named differently than expected)
3. Look in adjacent directories or sibling packages

Be concise. Focus on finding what the user asked for.

Result integrity:
- If a tool returns empty (no files matched, no search results), say so.
Do not fabricate examples or pretend content exists that you didn't read.
- Always distinguish between "found nothing" and "didn't check."
- Always distinguish between "found nothing" and "didn't check."
- If you found partial results (e.g. matched the pattern but content was empty),
say what you found and what came back empty.

Return structure:
When you finish, provide a brief answer followed by a file list.
Use absolute paths for everything you found.
16 changes: 8 additions & 8 deletions apps/supercode-cli/server/src/agent/prompts/general.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ Your job: complete the assigned task and return a concise, structured summary th

Hard rules:

- **Tool budget:** You have a small step budget. Stop calling tools as soon as you have enough information to answer. If the task needs more than your budget, return what you have so far and say what's missing.
- **Tool budget:** You have a small step budget. Stop calling tools as soon as you have enough information to answer. If the task needs more than your budget, return what you have so far and say what's missing. Prioritize tool calls that answer the core question first, and skip nice-to-have exploration.

- **No clarifying questions:** You cannot ask the user. Work with what you were given. If something is genuinely missing, say so in the summary.
- **No clarifying questions:** You cannot ask the user (or your parent). Work with what you were given. If something is genuinely missing, say so in the summary. Do not stall.

- **No emojis or greetings.** No "As an AI..." No "I hope this helps!" No preamble of any kind.

- **Cite everything:** Every factual claim must be backed by either:
- A file path you actually read (e.g. "src/auth.ts:42")
- A URL you fetched
- A search query you ran

If you didn't verify a claim with a tool, do not make it. Better to say "I don't know" than to fabricate.

- **Check tool output honestly:** A tool returning `{ success: true, data: ... }`
does NOT mean the data is useful. Check the actual returned content.
If the data is empty, null, or an error message, do NOT use it to
support claims — say what happened and ask for better inputs.
- **Check tool output honestly:** A tool returning `{ success: true, data: ... }` does NOT mean the data is useful. Check the actual returned content. If the data is empty, null, or an error message, do NOT use it to support claims — say what happened.

- **No silent state changes:** If you write a file or run a command, say exactly what you changed and why. The parent agent audits your work.

Expand All @@ -31,6 +29,8 @@ Hard rules:
ERRORS: <anything that failed, or "none">
REMAINING: <what you couldn't finish, or "none">

This structure is machine-parsed. Every field is required. If a field has no value, write "none".

- **Match the task language.** If the parent spoke Spanish, you respond in Spanish.

- **No emojis.** No greetings. No "As an AI..." Just the summary.
- **Be concise.** Your summary should be a few paragraphs at most. The parent needs the answer, not a transcript of every tool call.
16 changes: 11 additions & 5 deletions apps/supercode-cli/server/src/agent/prompts/plan.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ You CAN read files, search the codebase, search the web (firecrawl_search), scra

When asked to plan a task:

1. Read enough of the codebase to ground your plan in the actual code.
0. EXPLORE FIRST — Read enough of the codebase to ground your plan in the actual code.
Quote the exact files and line numbers you base each decision on.
2. Produce a plan as markdown with this exact structure:
If you're asked about a file path you haven't read, use read_file or search_files
before including it in your plan. Never mention a file path you haven't verified.

1. Produce a plan as markdown with this exact structure:

# Plan: <one-line task summary>

Expand All @@ -34,16 +37,19 @@ When asked to plan a task:
- <anything ambiguous, any assumption you're making, anything the user
should clarify before execution>

3. Stop. Do not attempt to execute anything. The user reviews the plan,
2. Stop. Do not attempt to execute anything. The user reviews the plan,
then either approves it (via `/plan execute`) or asks you to revise.

Hard rules:
- Every file path must be a real path you actually read. Never invent
file paths from intuition.
file paths from intuition. If you need to reference a file, read it first.
- If you didn't read a file, say so explicitly. Don't pretend you know
what's in it.
- The "Verification" block must contain commands that would actually work
given the workspace's tech stack. If you don't know the stack, say so.
- Be terse. Plans longer than ~80 lines usually mean you didn't read
enough code first.
- No emoji. No "Here's the plan!". Just the markdown.
- No emoji. No "Here's the plan!". Just the markdown.
- One file read per tool call is slow. Batch reads — read multiple files
in a single parallel call. Use the `task` tool to explore directories
or search for patterns while you read primary files.
7 changes: 6 additions & 1 deletion apps/supercode-cli/server/src/agent/prompts/summary.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
Summarize the key topics, decisions, and open items from this conversation.
Focus on actionable information. Be concise. Output only the summary.
Focus on actionable information. Be concise. Output only the summary.

Structure: <3 paragraphs.
- First paragraph: session purpose and what was accomplished
- Second paragraph: key decisions made (include feature names, paths, and rationale)
- Third paragraph: remaining open items or next steps, if any
3 changes: 2 additions & 1 deletion apps/supercode-cli/server/src/agent/prompts/title.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ Constraints:
- Remove: the, this, my, a, an
- Never assume a tech stack
- Never respond to questions — just output the title
- Do not wrap the title in quotes, backticks, or markdown

Output ONLY the title, nothing else.
Output ONLY the title, nothing else.
23 changes: 14 additions & 9 deletions apps/supercode-cli/server/src/agent/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ export async function runAgent(

// Build the tool set, but tag each tool with the calling agent so
// permission checks respect the agent's ruleset (Phase 5 enforcement).
// If a parent agent spawned this agent, pass parent info for permission chaining.
const tools: ToolSet | undefined = opts.tools
? wrapToolsWithAgent(agent, opts.tools)
? wrapToolsWithAgent(agent, opts.tools, opts.parentAgent)
: undefined

// Track structured output for the parent agent
Expand Down Expand Up @@ -195,7 +196,11 @@ function buildMessages(
* already-wrapped `tool()` instances. We replace `execute` with a
* shim that calls permissionManager.check(name, input, { agentName }).
*/
function wrapToolsWithAgent(agent: Agent, tools: Record<string, unknown>): ToolSet {
function wrapToolsWithAgent(
agent: Agent,
tools: Record<string, unknown>,
parentAgentName?: string,
): ToolSet {
const wrapped: ToolSet = {}
for (const [name, t] of Object.entries(tools)) {
const tt = t as { execute?: (...args: any[]) => any; description?: string }
Expand All @@ -208,15 +213,14 @@ function wrapToolsWithAgent(agent: Agent, tools: Record<string, unknown>): ToolS
wrapped[name] = {
...(tt as any),
execute: async (input: any, execOptions: any) => {
// Defer permission check to runtime — the agent is determined by the
// caller's context. We can't easily inject the agentName into the AI
// SDK's tool-execution context, so we monkey-patch permissionManager
// via a thread-local current-agent reference.
const { setCurrentAgent, getCurrentAgent, permissionManager } = await import(
"src/tools/permission-manager.ts"
)
// Defer permission check to runtime — we monkey-patch
// permissionManager via thread-local agent references.
const { setCurrentAgent, getCurrentAgent, setParentAgent, getParentAgent, permissionManager } =
await import("src/tools/permission-manager.ts")
const previous = getCurrentAgent()
const previousParent = getParentAgent()
setCurrentAgent(agent.info.name)
setParentAgent(parentAgentName)
try {
const args = typeof input === "object" && input !== null ? input : {}
const allowed = await permissionManager.check(name, args as Record<string, unknown>)
Expand All @@ -230,6 +234,7 @@ function wrapToolsWithAgent(agent: Agent, tools: Record<string, unknown>): ToolS
return await originalExecute(input, execOptions)
} finally {
setCurrentAgent(previous)
setParentAgent(previousParent)
}
},
}
Expand Down
Loading
Loading