From 7d676824b6545b359fbec527ff0e35ea9db871a9 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 14:27:50 +0530 Subject: [PATCH 01/13] feat(init): preserve provider choices --- package.json | 2 +- src/onboarding.test.ts | 46 ++++++++++++++++++++++++++++++++++++++++++ src/onboarding.ts | 31 ++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/onboarding.test.ts create mode 100644 src/onboarding.ts diff --git a/package.json b/package.json index a87531b4..b6e62669 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "dev": "node scripts/dev-server.mjs", "postinstall": "node scripts/fix-node-pty-permissions.mjs", "start": "node dist/cli.js serve", - "test": "tsx src/config.test.ts && tsx src/cli-workspace.test.ts && tsx src/request-meta.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/local-agent-config.test.ts && tsx src/local-agent-catalog.test.ts && tsx src/local-agent-runtime.test.ts && tsx src/local-agent-daemon-lifecycle.test.ts && tsx src/local-agent-daemon-protocol.test.ts && tsx src/local-agent-daemon.test.ts && tsx src/local-agent-codex.test.ts && tsx src/local-agent-opencode.test.ts && tsx src/local-agent-acp.test.ts && tsx src/local-agent-pi-sandbox.test.ts && tsx src/local-agent-pi.test.ts && tsx src/local-agent-claude.test.ts && tsx src/local-agent-adapters.test.ts && tsx src/local-agent-availability.test.ts && tsx src/local-agent-profiles.test.ts && tsx src/local-agent-targets.test.ts && tsx src/local-agent-store.test.ts && tsx src/local-agent-manager.test.ts && tsx src/roots.test.ts && tsx src/skills.test.ts && tsx src/workspaces.test.ts && tsx src/workspace-conversation.test.ts && tsx src/review-checkpoints.test.ts && tsx src/server.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts", + "test": "tsx src/config.test.ts && tsx src/onboarding.test.ts && tsx src/cli-workspace.test.ts && tsx src/request-meta.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/local-agent-config.test.ts && tsx src/local-agent-catalog.test.ts && tsx src/local-agent-runtime.test.ts && tsx src/local-agent-daemon-lifecycle.test.ts && tsx src/local-agent-daemon-protocol.test.ts && tsx src/local-agent-daemon.test.ts && tsx src/local-agent-codex.test.ts && tsx src/local-agent-opencode.test.ts && tsx src/local-agent-acp.test.ts && tsx src/local-agent-pi-sandbox.test.ts && tsx src/local-agent-pi.test.ts && tsx src/local-agent-claude.test.ts && tsx src/local-agent-adapters.test.ts && tsx src/local-agent-availability.test.ts && tsx src/local-agent-profiles.test.ts && tsx src/local-agent-targets.test.ts && tsx src/local-agent-store.test.ts && tsx src/local-agent-manager.test.ts && tsx src/roots.test.ts && tsx src/skills.test.ts && tsx src/workspaces.test.ts && tsx src/workspace-conversation.test.ts && tsx src/review-checkpoints.test.ts && tsx src/server.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts", "typecheck": "tsc -p tsconfig.json --noEmit" }, "keywords": [], diff --git a/src/onboarding.test.ts b/src/onboarding.test.ts new file mode 100644 index 00000000..edf95eba --- /dev/null +++ b/src/onboarding.test.ts @@ -0,0 +1,46 @@ +import assert from "node:assert/strict"; +import { + SUBAGENT_SKILL_INSTALL_COMMAND, + updateOnboardingSubagentsConfig, +} from "./onboarding.js"; + +assert.deepEqual( + updateOnboardingSubagentsConfig( + { enabled: false, providers: [] }, + true, + ["codex", "claude"], + ), + { + enabled: true, + providers: [ + { id: "codex", enabled: true }, + { id: "claude", enabled: true }, + ], + }, +); + +const configured = { + enabled: true, + providers: [ + { id: "codex" as const, enabled: true, model: "gpt-5.4", effort: "high" }, + { id: "claude" as const, enabled: true, model: "sonnet" }, + ], +}; +assert.deepEqual( + updateOnboardingSubagentsConfig(configured, true, ["claude"]), + { + enabled: true, + providers: [ + { id: "codex", enabled: false, model: "gpt-5.4", effort: "high" }, + { id: "claude", enabled: true, model: "sonnet" }, + ], + }, +); +assert.deepEqual( + updateOnboardingSubagentsConfig(configured, false, []), + { ...configured, enabled: false }, +); +assert.equal( + SUBAGENT_SKILL_INSTALL_COMMAND, + "npx skills add Waishnav/devspace --skill subagent-delegation --global", +); diff --git a/src/onboarding.ts b/src/onboarding.ts new file mode 100644 index 00000000..898e0faf --- /dev/null +++ b/src/onboarding.ts @@ -0,0 +1,31 @@ +import type { SubagentsConfig } from "./local-agent-config.js"; +import { + LOCAL_AGENT_PROVIDERS, + type LocalAgentProvider, +} from "./local-agent-profiles.js"; + +export const SUBAGENT_SKILL_INSTALL_COMMAND = + "npx skills add Waishnav/devspace --skill subagent-delegation --global"; + +export function updateOnboardingSubagentsConfig( + current: SubagentsConfig, + enabled: boolean, + selectedProviders: readonly LocalAgentProvider[], +): SubagentsConfig { + if (!enabled) return { ...current, enabled: false }; + + const selected = new Set(selectedProviders); + return { + enabled: true, + providers: LOCAL_AGENT_PROVIDERS + .filter((id) => selected.has(id) || current.providers.some((provider) => provider.id === id)) + .map((id) => { + const existing = current.providers.find((provider) => provider.id === id); + return { + ...existing, + id, + enabled: selected.has(id), + }; + }), + }; +} From 5bffbf139152e3cb4a96fb56e0a74d23fdf486f3 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 14:30:35 +0530 Subject: [PATCH 02/13] feat(init): onboard remote and local subagents --- src/cli.ts | 141 +++++++++++++++++++++++++++++++++++---------- src/config.test.ts | 15 +---- src/user-config.ts | 25 +------- 3 files changed, 113 insertions(+), 68 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 148571b4..ea58b38e 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -8,6 +8,7 @@ import { getShellConfig } from "@earendil-works/pi-coding-agent"; import { satisfies } from "semver"; import { loadConfig } from "./config.js"; import { resolveCliWorkspaceContext } from "./cli-workspace.js"; +import { resolveSubagentsConfig } from "./local-agent-config.js"; import { getLocalAgentProviderAvailabilitySnapshot, } from "./local-agent-availability.js"; @@ -18,6 +19,7 @@ import { formatLocalAgentProviderStatusSummary, } from "./local-agent-catalog.js"; import { loadLocalAgentProfiles } from "./local-agent-profiles.js"; +import type { LocalAgentProvider } from "./local-agent-profiles.js"; import { parseLocalAgentContinueArgs, parseLocalAgentRunArgs, @@ -26,10 +28,12 @@ import { createLocalAgentClient } from "./local-agent-client.js"; import { toAgentErrorPayload, type LocalAgentError } from "./local-agent-errors.js"; import type { LocalAgentRecord } from "./local-agent-store.js"; import { - ensureDevspaceDefaultSkills, + SUBAGENT_SKILL_INSTALL_COMMAND, + updateOnboardingSubagentsConfig, +} from "./onboarding.js"; +import { generateOwnerToken, loadDevspaceFiles, - resolveSubagentsFlag, writeDevspaceAuth, writeDevspaceConfig, type DevspaceUserConfig, @@ -134,31 +138,78 @@ async function runInit({ force }: { force: boolean }): Promise { }); const port = Number(portAnswer); - prompts.note( - [ - "DevSpace needs a public base URL so ChatGPT or Claude can reach this MCP server.", - "Create a tunnel or reverse proxy with Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or your own HTTPS proxy.", - "Paste the public origin here, without /mcp.", - "", - "Example: https://your-tunnel-host.example.com", - ].join("\n"), - "Public URL required", + const useRemoteMcp = await confirmPrompt({ + message: "Will a remote MCP host such as ChatGPT connect to DevSpace?", + initialValue: Boolean(files.config.publicBaseUrl), + }); + let publicBaseUrl: string | null = null; + if (useRemoteMcp) { + prompts.note( + [ + "Create a user-controlled tunnel or reverse proxy so the remote host can reach DevSpace.", + "Paste its public origin without /mcp.", + "", + "Example: https://your-tunnel-host.example.com", + ].join("\n"), + "Remote MCP access", + ); + publicBaseUrl = normalizePublicBaseUrl(await textPrompt({ + message: files.config.publicBaseUrl + ? `What is the public base URL? Press Enter to keep ${files.config.publicBaseUrl}` + : "What is the public base URL?", + placeholder: files.config.publicBaseUrl ?? "https://your-tunnel-host.example.com", + defaultValue: files.config.publicBaseUrl ?? "", + validate: validateRequiredPublicBaseUrl, + })); + } + + const useLocalHarness = await confirmPrompt({ + message: "Will you use DevSpace subagents from a local coding harness?", + initialValue: !useRemoteMcp, + }); + const currentSubagents = resolveSubagentsConfig(files.config.subagents, {}); + const enableSubagents = await confirmPrompt({ + message: "Enable DevSpace subagents?", + initialValue: currentSubagents.enabled, + }); + let selectedProviders: LocalAgentProvider[] = []; + if (enableSubagents) { + const availability = getLocalAgentProviderAvailabilitySnapshot(); + const configuredProviders = currentSubagents.providers + .filter((provider) => provider.enabled) + .map((provider) => provider.id); + const initialValues = configuredProviders.length > 0 + ? configuredProviders + : availability + .filter((provider) => provider.available) + .map((provider) => provider.name); + const providerAnswer = await prompts.multiselect({ + message: "Which providers may DevSpace launch?", + options: availability.map((provider) => ({ + value: provider.name, + label: provider.name, + hint: provider.available + ? provider.note ?? "available" + : `unavailable: ${provider.reason ?? "provider preflight failed"}`, + })), + initialValues, + required: true, + }); + if (prompts.isCancel(providerAnswer)) throw new SetupCancelledError(); + selectedProviders = providerAnswer as LocalAgentProvider[]; + } + const subagents = updateOnboardingSubagentsConfig( + currentSubagents, + enableSubagents, + selectedProviders, ); - const publicBaseUrl = normalizePublicBaseUrl(await textPrompt({ - message: files.config.publicBaseUrl - ? `What is the public base URL? Press Enter to keep ${files.config.publicBaseUrl}` - : "What is the public base URL?", - placeholder: files.config.publicBaseUrl ?? "https://your-tunnel-host.example.com", - defaultValue: files.config.publicBaseUrl ?? "", - validate: validateRequiredPublicBaseUrl, - })); const config: DevspaceUserConfig = { host: files.config.host ?? "127.0.0.1", port, allowedRoots, publicBaseUrl, - subagents: files.config.subagents, + subagents, }; const auth = { ownerToken: files.auth.ownerToken ?? generateOwnerToken(), @@ -166,25 +217,45 @@ async function runInit({ force }: { force: boolean }): Promise { const configPath = writeDevspaceConfig(config); const authPath = writeDevspaceAuth(auth); - const seededSkillPaths = resolveSubagentsFlag(config) ? ensureDevspaceDefaultSkills() : []; const lines = [ `Config: ${configPath}`, `Auth: ${authPath}`, - ...seededSkillPaths.map((path) => `Default skill: ${path}`), `Local MCP URL: http://${config.host}:${config.port}/mcp`, ...(publicBaseUrl ? [`Public MCP URL: ${publicBaseUrl}/mcp`] : []), ]; prompts.note(lines.join("\n"), "DevSpace configured"); - prompts.note( - [ - `Owner password: ${auth.ownerToken}`, - "Use this when ChatGPT or Claude asks you to approve DevSpace access.", - `Stored at: ${authPath}`, - ].join("\n"), - "Owner password", - ); - prompts.outro("Run `devspace serve` to start the MCP server."); + if (useRemoteMcp) { + prompts.note( + [ + `Owner password: ${auth.ownerToken}`, + "Use this when the remote MCP host asks you to approve DevSpace access.", + `Stored at: ${authPath}`, + ].join("\n"), + "Owner password", + ); + } + if (useLocalHarness && subagents.enabled) { + prompts.note( + [ + SUBAGENT_SKILL_INSTALL_COMMAND, + "", + "The Skills CLI will let you choose the local harnesses that receive it.", + "DevSpace does not write into harness skill directories during setup.", + ].join("\n"), + "Install the Subagents skill", + ); + } + const nextSteps = [ + useRemoteMcp ? "Run `devspace serve` to start the MCP server." : undefined, + useLocalHarness && subagents.enabled + ? "Run the skill command above before delegating from a local harness." + : undefined, + !useRemoteMcp && !(useLocalHarness && subagents.enabled) + ? "Run `devspace agents targets` to inspect the local configuration." + : undefined, + ].filter(Boolean).join(" "); + prompts.outro(nextSteps); } catch (error) { if (error instanceof SetupCancelledError) { prompts.cancel("Setup cancelled"); @@ -601,6 +672,14 @@ async function textPrompt(options: TextPromptOptions): Promise { return value || options.defaultValue; } +async function confirmPrompt( + options: Parameters[0], +): Promise { + const result = await prompts.confirm(options); + if (prompts.isCancel(result)) throw new SetupCancelledError(); + return result; +} + function validatePort(value: string | undefined): string | undefined { const port = Number(value); return Number.isInteger(port) && port >= 1 && port <= 65535 diff --git a/src/config.test.ts b/src/config.test.ts index 5e2b5f7f..dbf028d3 100644 --- a/src/config.test.ts +++ b/src/config.test.ts @@ -1,9 +1,8 @@ import assert from "node:assert/strict"; -import { existsSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs"; +import { mkdtempSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { loadConfig } from "./config.js"; -import { ensureDevspaceDefaultSkills, resolveSubagentsFlag } from "./user-config.js"; const emptyConfigDir = mkdtempSync(join(tmpdir(), "devspace-empty-config-test-")); const baseEnv = { @@ -39,18 +38,6 @@ assert.deepEqual(loadConfig({ ...baseEnv, DEVSPACE_SUBAGENTS: "1" }).subagents, enabled: true, providers: [], }); -assert.equal(resolveSubagentsFlag({}, {}), undefined); -assert.equal(resolveSubagentsFlag({ subagents: true }, {}), true); -assert.equal(resolveSubagentsFlag({ subagents: true }, { DEVSPACE_SUBAGENTS: "0" }), false); -assert.equal(resolveSubagentsFlag({}, { DEVSPACE_SUBAGENTS: "1" }), true); - -const seededConfigDir = mkdtempSync(join(tmpdir(), "devspace-seeded-skills-test-")); -const seededSkillPaths = ensureDevspaceDefaultSkills({ DEVSPACE_CONFIG_DIR: seededConfigDir }); -assert.deepEqual(seededSkillPaths, [join(seededConfigDir, "skills", "subagent-delegation", "SKILL.md")]); -assert.equal(existsSync(seededSkillPaths[0]), true); -assert.match(readFileSync(seededSkillPaths[0], "utf8"), /name: subagent-delegation/); -assert.deepEqual(ensureDevspaceDefaultSkills({ DEVSPACE_CONFIG_DIR: seededConfigDir }), []); - assert.throws( () => loadConfig({ ...baseEnv, DEVSPACE_WIDGETS: "invalid" }), /Invalid DEVSPACE_WIDGETS: invalid/, diff --git a/src/user-config.ts b/src/user-config.ts index f2e681f2..98d05ac6 100644 --- a/src/user-config.ts +++ b/src/user-config.ts @@ -6,12 +6,9 @@ import { writeFileSync, } from "node:fs"; import { homedir } from "node:os"; -import { dirname, join, resolve } from "node:path"; +import { join, resolve } from "node:path"; import { expandHomePath } from "./roots.js"; -import { - resolveSubagentsConfig, - type StoredSubagentsConfig, -} from "./local-agent-config.js"; +import type { StoredSubagentsConfig } from "./local-agent-config.js"; export interface DevspaceUserConfig { host?: string; @@ -103,24 +100,6 @@ export function generateOwnerToken(): string { return randomBytes(32).toString("base64url"); } -export function ensureDevspaceDefaultSkills(env: NodeJS.ProcessEnv = process.env): string[] { - const targetPath = join(devspaceSkillsDir(env), "subagent-delegation", "SKILL.md"); - if (existsSync(targetPath)) return []; - - const sourcePath = new URL("../skills/subagent-delegation/SKILL.md", import.meta.url); - mkdirSync(dirname(targetPath), { recursive: true }); - writeFileSync(targetPath, readFileSync(sourcePath, "utf8"), { mode: 0o644 }); - return [targetPath]; -} - -export function resolveSubagentsFlag( - config: Pick, - env: NodeJS.ProcessEnv = process.env, -): boolean | undefined { - if (config.subagents === undefined && env.DEVSPACE_SUBAGENTS === undefined) return undefined; - return resolveSubagentsConfig(config.subagents, env).enabled; -} - function readJsonFile(filePath: string): T { try { return JSON.parse(readFileSync(filePath, "utf8")) as T; From 89a0bc95922cbe2dc32ca8addcec2aa5dec6cc3f Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 14:31:54 +0530 Subject: [PATCH 03/13] docs(init): guide local harness setup --- README.md | 17 +++++++++----- docs/chatgpt-coding-workflow.md | 16 ++++++------- docs/configuration.md | 14 ++++++++--- docs/gotchas.md | 18 +++++++++++---- docs/setup.md | 36 ++++++++++++++++++++++++----- skills/subagent-delegation/SKILL.md | 11 ++++++--- 6 files changed, 82 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 69a9d743..9f275e74 100644 --- a/README.md +++ b/README.md @@ -66,26 +66,28 @@ Install the DevSpace CLI: npm install -g @waishnav/devspace ``` -Then initialize and start the server: +Then initialize DevSpace: ```bash devspace init -devspace serve ``` Or run it without a global install: ```bash npx @waishnav/devspace init -npx @waishnav/devspace serve ``` During setup, DevSpace asks for: -- the local project folders ChatGPT is allowed to open through DevSpace +- the local project folders DevSpace is allowed to open - the local port, usually `7676` -- your public HTTPS base URL from Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or - another reverse proxy +- whether a remote MCP host and/or local coding harness will use DevSpace +- which subagent providers DevSpace may launch + +If a remote MCP host will connect, setup also asks for your public HTTPS base +URL from Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or another reverse +proxy. Local-harness-only setups do not need a tunnel or public URL. Use the public origin without `/mcp` during setup: @@ -94,6 +96,9 @@ https://your-tunnel-host.example.com ``` You will configure your MCP client with the public `/mcp` URL after setup. +Run `devspace serve` when using the MCP server. For a local coding harness, +setup prints a `skills` command that installs DevSpace's Subagents skill into +the harnesses you choose; DevSpace does not write into their skill directories. When the client connects, DevSpace opens an Owner password approval page. Enter the Owner password printed by `devspace init`. It is also stored in: diff --git a/docs/chatgpt-coding-workflow.md b/docs/chatgpt-coding-workflow.md index 1ec7fe57..90d53180 100644 --- a/docs/chatgpt-coding-workflow.md +++ b/docs/chatgpt-coding-workflow.md @@ -116,7 +116,7 @@ DevSpace discovers standard Agent Skills from: It also keeps compatibility with: -- the bundled `subagent-delegation` skill when `DEVSPACE_SUBAGENTS=1`, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists +- the bundled `subagent-delegation` skill when Subagents are enabled, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists - `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills` - additional paths from `DEVSPACE_SKILL_PATHS` @@ -140,13 +140,13 @@ Skill paths may be outside the workspace. DevSpace only permits reading: - advertised `SKILL.md` files - files under a skill directory after that skill's `SKILL.md` has been read -Set `DEVSPACE_SKILLS=0` to hide skills from workspace output. Set -`DEVSPACE_SUBAGENTS=1` to expose the experimental subagent catalog and -`subagent-delegation` skill. That skill teaches the minimal -`devspace agents ls`, `devspace agents run`, `devspace agents continue`, and -`devspace agents show` -workflow. The catalog comes from `open_workspace`; `devspace agents ls` lists -existing subagent sessions for that workspace. +Set `DEVSPACE_SKILLS=0` to hide skills from workspace output. Enable Subagents +and choose providers through `devspace init` or the persisted provider +configuration. The bundled `subagent-delegation` skill teaches the minimal +`devspace agents targets`, `devspace agents ls`, `devspace agents run`, +`devspace agents continue`, and `devspace agents show` workflow. The catalog +comes from `open_workspace`; `devspace agents ls` lists existing subagent +sessions for that workspace. ## Tool Names diff --git a/docs/configuration.md b/docs/configuration.md index 997e5b5d..5aa7b3e2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -136,7 +136,7 @@ DevSpace discovers standard Agent Skills from: It also keeps compatibility with: -- the bundled `subagent-delegation` skill when `DEVSPACE_SUBAGENTS=1`, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists +- the bundled `subagent-delegation` skill when Subagents are enabled, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists - `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills` - additional paths from `DEVSPACE_SKILL_PATHS` @@ -187,8 +187,16 @@ providers and their profiles are omitted from this model-facing catalog. `devspa lists existing subagent sessions for the current workspace, scoped by the workspace environment injected into shell commands. The `subagent-delegation` skill teaches the model to use only the minimal `devspace agents ls`, -`devspace agents run`, `devspace agents continue`, and `devspace agents show` -workflow. +`devspace agents targets`, `devspace agents run`, `devspace agents continue`, +and `devspace agents show` workflow. + +For Codex, Claude Code, OpenCode, Pi, or another supported local harness, use +the Skills CLI to install the same skill. DevSpace setup prints this command but +does not run it or write into harness directories: + +```bash +npx skills add Waishnav/devspace --skill subagent-delegation --global +``` Starter profile templates are available under `examples/agents/`. Copy or adapt them into one of the active profile directories before use. diff --git a/docs/gotchas.md b/docs/gotchas.md index 5769d3e0..f9412440 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -216,21 +216,31 @@ DevSpace looks in standard Agent Skills locations: It also checks compatibility and custom paths: -- the bundled `subagent-delegation` skill when `DEVSPACE_SUBAGENTS=1`, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists +- the bundled `subagent-delegation` skill when Subagents are enabled, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists - `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills` - additional paths from `DEVSPACE_SKILL_PATHS` -When `DEVSPACE_SUBAGENTS=1`, DevSpace loads agent profiles from +When Subagents are enabled, DevSpace loads agent profiles from `~/.devspace/agents/*.md` and project `.devspace/agents/*.md`, then exposes a compact profile catalog through `open_workspace`. The bundled `subagent-delegation` skill keeps the model-facing workflow to -`devspace agents ls`, `devspace agents run`, `devspace agents continue`, and -`devspace agents show`. +`devspace agents targets`, `devspace agents ls`, `devspace agents run`, +`devspace agents continue`, and `devspace agents show`. Those commands automatically manage the internal local agent daemon; `devspace serve` is not a prerequisite. `devspace agents ls` lists existing subagent sessions, not profile definitions. +For a local coding harness, run the installation command printed by +`devspace init`: + +```bash +npx skills add Waishnav/devspace --skill subagent-delegation --global +``` + +The Skills CLI handles harness discovery and installation. DevSpace setup does +not copy files into harness skill directories. + Packaged agent profile examples under `examples/agents/` are starter templates. Copy or adapt them into one of the active profile directories before use. diff --git a/docs/setup.md b/docs/setup.md index e332f216..7d5d5399 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -1,7 +1,7 @@ # Setup Guide -This guide is for users who want ChatGPT or another MCP host to work in local -projects through DevSpace. +This guide covers both remote MCP hosts and local coding harnesses using +DevSpace in local projects. ## Requirements @@ -9,10 +9,12 @@ projects through DevSpace. - npm - Git - Bash, including Git Bash or WSL on Windows -- a public HTTPS URL that forwards to the local DevSpace server +- a public HTTPS URL that forwards to the local DevSpace server, only when a + remote MCP host will connect -DevSpace does not create the public tunnel for you. Use Cloudflare Tunnel, -ngrok, Pinggy, Tailscale Funnel, or your own HTTPS reverse proxy. +DevSpace does not create the public tunnel for you. Remote MCP users can use +Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or their own HTTPS reverse +proxy. ## Install And Configure @@ -53,7 +55,26 @@ The local MCP URL is: http://127.0.0.1:7676/mcp ``` -### Public Base URL +### Usage And Subagents + +Setup asks independently whether a remote MCP host will connect and whether a +local coding harness will use DevSpace subagents. It then detects the supported +providers and asks which ones DevSpace may launch. These choices are persisted +as provider objects under `subagents` in `~/.devspace/config.json`. + +For a local harness, setup prints this command instead of modifying harness +directories itself: + +```bash +npx skills add Waishnav/devspace --skill subagent-delegation --global +``` + +The Skills CLI asks which installed harnesses should receive the skill. The +skill uses `devspace agents targets`, `run`, `continue`, `show`, and `ls`; these +commands start DevSpace's local agent daemon as needed and do not require +`devspace serve`. + +### Public Base URL For Remote MCP Start your tunnel or reverse proxy before entering this value. Point the tunnel at: @@ -74,6 +95,9 @@ Configure the MCP client with the full MCP endpoint: https://your-tunnel-host.example.com/mcp ``` +Skip remote MCP access during setup for a local-harness-only configuration; no +public URL is required. + ## Start The Server Run: diff --git a/skills/subagent-delegation/SKILL.md b/skills/subagent-delegation/SKILL.md index 24fc7266..10d558c9 100644 --- a/skills/subagent-delegation/SKILL.md +++ b/skills/subagent-delegation/SKILL.md @@ -17,12 +17,17 @@ being used. Use only these commands for normal delegation: ```bash +devspace agents targets devspace agents ls devspace agents run "" devspace agents continue "" devspace agents show ``` +`targets` shows the providers and profiles usable from the current workspace. +Use it when this skill is installed directly in a local coding harness. An MCP +host may already have received the same compact catalog from `open_workspace`. + `ls` shows existing subagent sessions for the current workspace. DevSpace scopes it automatically from the shell environment injected by the workspace tool. Use the returned logical `agt_...` ID with `continue`; provider session IDs and @@ -60,9 +65,9 @@ DevSpace agent integration. ## Choosing a profile Choose profiles from the compact subagent profile catalog returned by -`open_workspace`. Use the profile name with `devspace agents run`. If no -profile fits and delegation is still appropriate, use a built-in provider name -from `open_workspace`. +`open_workspace` or `devspace agents targets`. Use the profile name with +`devspace agents run`. If no profile fits and delegation is still appropriate, +use a provider listed by the same catalog. Profiles may declare a model and optional effort level. To override the configured/default provider model or effort level for a run, pass `--model` From 70fb3825ebcccd4f95a070a51481e05455cf086f Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 18:54:51 +0530 Subject: [PATCH 04/13] feat(init): tailor setup to usage --- src/cli.ts | 156 ++++++++++++++++++----------------------- src/onboarding.test.ts | 21 ++++-- src/onboarding.ts | 27 +++++-- 3 files changed, 107 insertions(+), 97 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index ea58b38e..408142cb 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -28,8 +28,12 @@ import { createLocalAgentClient } from "./local-agent-client.js"; import { toAgentErrorPayload, type LocalAgentError } from "./local-agent-errors.js"; import type { LocalAgentRecord } from "./local-agent-store.js"; import { + type OnboardingDestination, SUBAGENT_SKILL_INSTALL_COMMAND, + resolveOnboardingUsage, updateOnboardingSubagentsConfig, + usesChatGpt, + usesCodingAgents, } from "./onboarding.js"; import { generateOwnerToken, @@ -117,9 +121,31 @@ async function runInit({ force }: { force: boolean }): Promise { try { prompts.intro("DevSpace setup"); + const destinationAnswer = await prompts.multiselect({ + message: "Where will you use DevSpace?", + options: [ + { + value: "chatgpt", + label: "ChatGPT", + hint: "Connect ChatGPT to projects on this computer.", + }, + { + value: "coding-agents", + label: "Coding Agents", + hint: "Use DevSpace from Codex, Claude Code, OpenCode, Pi, and similar tools.", + }, + ], + initialValues: files.config.publicBaseUrl ? ["chatgpt"] : ["coding-agents"], + required: true, + }); + if (prompts.isCancel(destinationAnswer)) throw new SetupCancelledError(); + const usage = resolveOnboardingUsage(destinationAnswer as OnboardingDestination[]); + const useChatGpt = usesChatGpt(usage); + const useCodingAgents = usesCodingAgents(usage); + const defaultRoots = files.config.allowedRoots?.join(", ") || process.cwd(); const rootsAnswer = await textPrompt({ - message: `Where are your projects located? Press Enter to use ${defaultRoots}`, + message: `Which project folders can DevSpace access? Press Enter to use ${defaultRoots}`, placeholder: defaultRoots, defaultValue: defaultRoots, validate: (value) => value?.trim() ? undefined : "Enter at least one project root.", @@ -129,78 +155,55 @@ async function runInit({ force }: { force: boolean }): Promise { .map((root) => resolve(expandHomePath(root.trim()))) .filter(Boolean); - const defaultPort = String(files.config.port ?? 7676); - const portAnswer = await textPrompt({ - message: `Which local port should DevSpace use? Press Enter to use ${defaultPort}`, - placeholder: defaultPort, - defaultValue: defaultPort, - validate: validatePort, - }); - const port = Number(portAnswer); + const port = isValidPort(files.config.port) ? files.config.port : 7676; - const useRemoteMcp = await confirmPrompt({ - message: "Will a remote MCP host such as ChatGPT connect to DevSpace?", - initialValue: Boolean(files.config.publicBaseUrl), - }); let publicBaseUrl: string | null = null; - if (useRemoteMcp) { + if (useChatGpt) { prompts.note( [ - "Create a user-controlled tunnel or reverse proxy so the remote host can reach DevSpace.", - "Paste its public origin without /mcp.", + `Point your HTTPS tunnel or reverse proxy to http://127.0.0.1:${port}.`, + "Paste its public URL below.", "", "Example: https://your-tunnel-host.example.com", ].join("\n"), - "Remote MCP access", + "Connect ChatGPT", ); publicBaseUrl = normalizePublicBaseUrl(await textPrompt({ message: files.config.publicBaseUrl - ? `What is the public base URL? Press Enter to keep ${files.config.publicBaseUrl}` - : "What is the public base URL?", + ? `What public URL will ChatGPT connect to? Press Enter to keep ${files.config.publicBaseUrl}` + : "What public URL will ChatGPT connect to?", placeholder: files.config.publicBaseUrl ?? "https://your-tunnel-host.example.com", defaultValue: files.config.publicBaseUrl ?? "", validate: validateRequiredPublicBaseUrl, })); } - const useLocalHarness = await confirmPrompt({ - message: "Will you use DevSpace subagents from a local coding harness?", - initialValue: !useRemoteMcp, - }); const currentSubagents = resolveSubagentsConfig(files.config.subagents, {}); - const enableSubagents = await confirmPrompt({ - message: "Enable DevSpace subagents?", - initialValue: currentSubagents.enabled, + const availability = getLocalAgentProviderAvailabilitySnapshot(); + const configuredProviders = currentSubagents.providers + .filter((provider) => provider.enabled) + .map((provider) => provider.id); + const initialValues = configuredProviders.length > 0 + ? configuredProviders + : availability + .filter((provider) => provider.available) + .map((provider) => provider.name); + const providerAnswer = await prompts.multiselect({ + message: "Which Coding Agents should be available?", + options: availability.map((provider) => ({ + value: provider.name, + label: provider.name, + hint: provider.available + ? provider.note ?? "available" + : `unavailable: ${provider.reason ?? "provider preflight failed"}`, + })), + initialValues, + required: true, }); - let selectedProviders: LocalAgentProvider[] = []; - if (enableSubagents) { - const availability = getLocalAgentProviderAvailabilitySnapshot(); - const configuredProviders = currentSubagents.providers - .filter((provider) => provider.enabled) - .map((provider) => provider.id); - const initialValues = configuredProviders.length > 0 - ? configuredProviders - : availability - .filter((provider) => provider.available) - .map((provider) => provider.name); - const providerAnswer = await prompts.multiselect({ - message: "Which providers may DevSpace launch?", - options: availability.map((provider) => ({ - value: provider.name, - label: provider.name, - hint: provider.available - ? provider.note ?? "available" - : `unavailable: ${provider.reason ?? "provider preflight failed"}`, - })), - initialValues, - required: true, - }); - if (prompts.isCancel(providerAnswer)) throw new SetupCancelledError(); - selectedProviders = providerAnswer as LocalAgentProvider[]; - } + if (prompts.isCancel(providerAnswer)) throw new SetupCancelledError(); + const selectedProviders = providerAnswer as LocalAgentProvider[]; const subagents = updateOnboardingSubagentsConfig( currentSubagents, - enableSubagents, selectedProviders, ); @@ -215,45 +218,37 @@ async function runInit({ force }: { force: boolean }): Promise { ownerToken: files.auth.ownerToken ?? generateOwnerToken(), }; - const configPath = writeDevspaceConfig(config); - const authPath = writeDevspaceAuth(auth); + writeDevspaceConfig(config); + writeDevspaceAuth(auth); const lines = [ - `Config: ${configPath}`, - `Auth: ${authPath}`, - `Local MCP URL: http://${config.host}:${config.port}/mcp`, - ...(publicBaseUrl ? [`Public MCP URL: ${publicBaseUrl}/mcp`] : []), + `Project folders: ${allowedRoots.join(", ")}`, + `Coding Agents: ${selectedProviders.join(", ")}`, + ...(publicBaseUrl ? [`ChatGPT connection URL: ${publicBaseUrl}/mcp`] : []), ]; - prompts.note(lines.join("\n"), "DevSpace configured"); - if (useRemoteMcp) { + prompts.note(lines.join("\n"), "DevSpace is ready"); + if (useChatGpt) { prompts.note( [ `Owner password: ${auth.ownerToken}`, - "Use this when the remote MCP host asks you to approve DevSpace access.", - `Stored at: ${authPath}`, + "Use this when ChatGPT asks you to approve DevSpace access.", ].join("\n"), "Owner password", ); } - if (useLocalHarness && subagents.enabled) { + if (useCodingAgents) { prompts.note( [ SUBAGENT_SKILL_INSTALL_COMMAND, "", - "The Skills CLI will let you choose the local harnesses that receive it.", - "DevSpace does not write into harness skill directories during setup.", + "The Skills CLI will let you choose which Coding Agents receive it.", ].join("\n"), "Install the Subagents skill", ); } const nextSteps = [ - useRemoteMcp ? "Run `devspace serve` to start the MCP server." : undefined, - useLocalHarness && subagents.enabled - ? "Run the skill command above before delegating from a local harness." - : undefined, - !useRemoteMcp && !(useLocalHarness && subagents.enabled) - ? "Run `devspace agents targets` to inspect the local configuration." - : undefined, + useChatGpt ? "Run `devspace serve`, then connect ChatGPT." : undefined, + useCodingAgents ? "Run the skill command above before delegating from your Coding Agents." : undefined, ].filter(Boolean).join(" "); prompts.outro(nextSteps); } catch (error) { @@ -672,19 +667,8 @@ async function textPrompt(options: TextPromptOptions): Promise { return value || options.defaultValue; } -async function confirmPrompt( - options: Parameters[0], -): Promise { - const result = await prompts.confirm(options); - if (prompts.isCancel(result)) throw new SetupCancelledError(); - return result; -} - -function validatePort(value: string | undefined): string | undefined { - const port = Number(value); - return Number.isInteger(port) && port >= 1 && port <= 65535 - ? undefined - : "Enter a port between 1 and 65535."; +function isValidPort(value: unknown): value is number { + return Number.isInteger(value) && Number(value) >= 1 && Number(value) <= 65535; } function validateRequiredPublicBaseUrl(value: string | undefined): string | undefined { diff --git a/src/onboarding.test.ts b/src/onboarding.test.ts index edf95eba..5d0ab4a6 100644 --- a/src/onboarding.test.ts +++ b/src/onboarding.test.ts @@ -1,13 +1,24 @@ import assert from "node:assert/strict"; import { + resolveOnboardingUsage, SUBAGENT_SKILL_INSTALL_COMMAND, updateOnboardingSubagentsConfig, + usesChatGpt, + usesCodingAgents, } from "./onboarding.js"; +assert.equal(resolveOnboardingUsage(["chatgpt"]), "chatgpt"); +assert.equal(resolveOnboardingUsage(["coding-agents"]), "coding-agents"); +assert.equal(resolveOnboardingUsage(["coding-agents", "chatgpt"]), "both"); +assert.equal(usesChatGpt("both"), true); +assert.equal(usesCodingAgents("both"), true); +assert.equal(usesChatGpt("coding-agents"), false); +assert.equal(usesCodingAgents("chatgpt"), false); +assert.throws(() => resolveOnboardingUsage([]), /Choose ChatGPT, Coding Agents, or both/); + assert.deepEqual( updateOnboardingSubagentsConfig( { enabled: false, providers: [] }, - true, ["codex", "claude"], ), { @@ -27,7 +38,7 @@ const configured = { ], }; assert.deepEqual( - updateOnboardingSubagentsConfig(configured, true, ["claude"]), + updateOnboardingSubagentsConfig(configured, ["claude"]), { enabled: true, providers: [ @@ -36,11 +47,7 @@ assert.deepEqual( ], }, ); -assert.deepEqual( - updateOnboardingSubagentsConfig(configured, false, []), - { ...configured, enabled: false }, -); assert.equal( SUBAGENT_SKILL_INSTALL_COMMAND, - "npx skills add Waishnav/devspace --skill subagent-delegation --global", + "npx skills add Waishnav/devspace --skill subagents --global", ); diff --git a/src/onboarding.ts b/src/onboarding.ts index 898e0faf..2642e776 100644 --- a/src/onboarding.ts +++ b/src/onboarding.ts @@ -5,15 +5,34 @@ import { } from "./local-agent-profiles.js"; export const SUBAGENT_SKILL_INSTALL_COMMAND = - "npx skills add Waishnav/devspace --skill subagent-delegation --global"; + "npx skills add Waishnav/devspace --skill subagents --global"; + +export const ONBOARDING_DESTINATIONS = ["chatgpt", "coding-agents"] as const; +export type OnboardingDestination = typeof ONBOARDING_DESTINATIONS[number]; +export type OnboardingUsage = OnboardingDestination | "both"; + +export function resolveOnboardingUsage( + destinations: readonly OnboardingDestination[], +): OnboardingUsage { + const selected = new Set(destinations); + if (selected.has("chatgpt") && selected.has("coding-agents")) return "both"; + if (selected.has("chatgpt")) return "chatgpt"; + if (selected.has("coding-agents")) return "coding-agents"; + throw new Error("Choose ChatGPT, Coding Agents, or both."); +} + +export function usesChatGpt(usage: OnboardingUsage): boolean { + return usage === "chatgpt" || usage === "both"; +} + +export function usesCodingAgents(usage: OnboardingUsage): boolean { + return usage === "coding-agents" || usage === "both"; +} export function updateOnboardingSubagentsConfig( current: SubagentsConfig, - enabled: boolean, selectedProviders: readonly LocalAgentProvider[], ): SubagentsConfig { - if (!enabled) return { ...current, enabled: false }; - const selected = new Set(selectedProviders); return { enabled: true, From 0a44f5526f7d9f8aaf3db60c8010ed0ceb1d8550 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 18:55:42 +0530 Subject: [PATCH 05/13] refactor(skills): rename subagent skill --- .../SKILL.md | 44 ++++++++----------- src/skills.test.ts | 18 ++++---- src/skills.ts | 14 +++--- 3 files changed, 34 insertions(+), 42 deletions(-) rename skills/{subagent-delegation => subagents}/SKILL.md (66%) diff --git a/skills/subagent-delegation/SKILL.md b/skills/subagents/SKILL.md similarity index 66% rename from skills/subagent-delegation/SKILL.md rename to skills/subagents/SKILL.md index 10d558c9..65ed8361 100644 --- a/skills/subagent-delegation/SKILL.md +++ b/skills/subagents/SKILL.md @@ -1,9 +1,9 @@ --- -name: subagent-delegation +name: subagents description: Delegate coding tasks to user-configured DevSpace subagents. --- -# Subagent Delegation +# Subagents Use this skill when the user explicitly asks to delegate work to another coding agent, use a named subagent, get a second opinion, compare approaches, or run @@ -24,20 +24,19 @@ devspace agents continue "" devspace agents show ``` -`targets` shows the providers and profiles usable from the current workspace. -Use it when this skill is installed directly in a local coding harness. An MCP -host may already have received the same compact catalog from `open_workspace`. +`targets` shows the providers and profiles available for the current project. +Use an agent or profile already presented by DevSpace. If you do not know which +ones are available, run `devspace agents targets` before delegating. -`ls` shows existing subagent sessions for the current workspace. DevSpace scopes -it automatically from the shell environment injected by the workspace tool. -Use the returned logical `agt_...` ID with `continue`; provider session IDs and -prefixes are not interchangeable with logical agent IDs. +`ls` shows existing subagent sessions for the current project. DevSpace selects +the project from the command environment. Use the returned `agt_...` ID with +`continue`. Provider session IDs cannot replace DevSpace agent IDs. `run ""` starts a new configured profile and prints a DevSpace agent id. -`run ""` starts a raw built-in provider when no configured -profile is needed. Built-in providers are listed by `open_workspace`. +`run ""` starts an enabled provider when no configured +profile is needed. Run `targets` if you do not know which providers are enabled. `continue ""` sends a follow-up to an existing agent. Do not use `run ` for continuation. @@ -53,21 +52,15 @@ devspace agents continue --effort "" running, `show` waits briefly. If there is still no final response, call `show` again later. -The commands automatically start the internal `devspace-agentd` process when -needed. `devspace serve` is not required for local-agent execution. The daemon -owns shared agent sessions and provider runtimes for the configured DevSpace -state directory. - -Do not run provider CLIs such as `codex`, `claude`, `opencode`, `pi`, -`cursor-agent`, or `copilot` directly unless you are explicitly debugging -DevSpace agent integration. +Use DevSpace commands for delegation instead of calling provider commands +directly. DevSpace manages execution and continuation for you. ## Choosing a profile -Choose profiles from the compact subagent profile catalog returned by -`open_workspace` or `devspace agents targets`. Use the profile name with -`devspace agents run`. If no profile fits and delegation is still appropriate, -use a provider listed by the same catalog. +Choose from the profiles DevSpace has already presented. If no catalog is +visible, run `devspace agents targets`. Use the profile name with +`devspace agents run`. If no profile fits, use an enabled provider from the +same result. Profiles may declare a model and optional effort level. To override the configured/default provider model or effort level for a run, pass `--model` @@ -80,9 +73,8 @@ devspace agents run --effort "" Use `--effort` only when the user asks for a specific reasoning depth or when the task clearly needs a different effort than the configured profile default. -Effort values are provider-specific passthrough values. Use names supported by -the selected local agent harness; DevSpace does not translate values between -providers. +Effort values are provider-specific. Use a value supported by the selected +provider. DevSpace does not translate values between providers. Good delegation targets: diff --git a/src/skills.test.ts b/src/skills.test.ts index 707dda26..9db16a10 100644 --- a/src/skills.test.ts +++ b/src/skills.test.ts @@ -31,10 +31,10 @@ try { await mkdir(join(projectClaudeSkills, "claude-project-skill"), { recursive: true }); await mkdir(join(projectRoot, ".pi", "skills", "project-skill"), { recursive: true }); await mkdir(join(agentDir, "skills", "global-skill"), { recursive: true }); - await mkdir(join(agentDir, "skills", "subagent-delegation"), { recursive: true }); + await mkdir(join(agentDir, "skills", "subagents"), { recursive: true }); await mkdir(join(explicitSkills, "duplicate"), { recursive: true }); await mkdir(join(explicitSkills, "disabled"), { recursive: true }); - await mkdir(join(explicitSkills, "subagent-delegation"), { recursive: true }); + await mkdir(join(explicitSkills, "subagents"), { recursive: true }); await mkdir(join(devspaceSkills, "devspace-local-skill"), { recursive: true }); await writeFile( @@ -126,10 +126,10 @@ try { ].join("\n"), ); await writeFile( - join(agentDir, "skills", "subagent-delegation", "SKILL.md"), + join(agentDir, "skills", "subagents", "SKILL.md"), [ "---", - "name: subagent-delegation", + "name: subagents", "description: Hidden subagent skill winner.", "---", "", @@ -137,10 +137,10 @@ try { ].join("\n"), ); await writeFile( - join(explicitSkills, "subagent-delegation", "SKILL.md"), + join(explicitSkills, "subagents", "SKILL.md"), [ "---", - "name: subagent-delegation", + "name: subagents", "description: Hidden subagent skill loser.", "---", "", @@ -184,13 +184,13 @@ try { assert.equal(loaded.skills.some((skill) => skill.name === "claude-project-skill"), true); assert.equal(loaded.skills.some((skill) => skill.name === "project-skill"), false); assert.equal(loaded.skills.some((skill) => skill.name === "devspace-local-skill"), true); - assert.equal(loaded.skills.some((skill) => skill.name === "subagent-delegation"), false); + assert.equal(loaded.skills.some((skill) => skill.name === "subagents"), false); assert.equal(loaded.skills.filter((skill) => skill.name === "duplicate-skill").length, 1); assert.equal(loaded.skills.some((skill) => skill.name === "hidden-skill"), true); assert.equal(loaded.diagnostics.some((diagnostic) => diagnostic.type === "collision"), true); assert.equal( loaded.diagnostics.some( - (diagnostic) => diagnostic.collision?.name === "subagent-delegation", + (diagnostic) => diagnostic.collision?.name === "subagents", ), false, ); @@ -204,7 +204,7 @@ try { }); assert.equal( loadWorkspaceSkills(experimentalConfig, projectRoot).skills.some( - (skill) => skill.name === "subagent-delegation", + (skill) => skill.name === "subagents", ), true, ); diff --git a/src/skills.ts b/src/skills.ts index eb9691e3..cf4fa332 100644 --- a/src/skills.ts +++ b/src/skills.ts @@ -21,15 +21,15 @@ export interface SkillReadResolution { isSkillFile: boolean; } -const SUBAGENT_DELEGATION_NAME = "subagent-delegation"; -const SUBAGENT_DELEGATION_SKILL = join(SUBAGENT_DELEGATION_NAME, "SKILL.md"); +const SUBAGENTS_SKILL_NAME = "subagents"; +const SUBAGENTS_SKILL = join(SUBAGENTS_SKILL_NAME, "SKILL.md"); function bundledSkillsDir(): string { return fileURLToPath(new URL("../skills", import.meta.url)); } -function hasSubagentDelegationSkill(skillDir: string): boolean { - return existsSync(join(skillDir, SUBAGENT_DELEGATION_SKILL)); +function hasSubagentsSkill(skillDir: string): boolean { + return existsSync(join(skillDir, SUBAGENTS_SKILL)); } export function effectiveSkillPaths(config: ServerConfig, cwd: string): string[] { @@ -39,7 +39,7 @@ export function effectiveSkillPaths(config: ServerConfig, cwd: string): string[] resolve(cwd, ".agents", "skills"), config.devspaceSkillsDir, join(config.agentDir, "skills"), - config.subagents.enabled && !hasSubagentDelegationSkill(config.devspaceSkillsDir) + config.subagents.enabled && !hasSubagentsSkill(config.devspaceSkillsDir) ? bundledSkills : undefined, ]; @@ -74,10 +74,10 @@ export function loadWorkspaceSkills(config: ServerConfig, cwd: string): LoadedSk if (config.subagents.enabled) return result; return { - skills: result.skills.filter((skill) => skill.name !== SUBAGENT_DELEGATION_NAME), + skills: result.skills.filter((skill) => skill.name !== SUBAGENTS_SKILL_NAME), diagnostics: result.diagnostics.filter((diagnostic) => { const collision = diagnostic.collision; - return !(collision?.resourceType === "skill" && collision.name === SUBAGENT_DELEGATION_NAME); + return !(collision?.resourceType === "skill" && collision.name === SUBAGENTS_SKILL_NAME); }), }; } From 79f8917f35be752ece5842c6d349f845c38b42cb Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 18:56:34 +0530 Subject: [PATCH 06/13] docs(init): explain usage-first setup --- README.md | 14 ++++----- docs/chatgpt-coding-workflow.md | 4 +-- docs/configuration.md | 10 +++--- docs/gotchas.md | 12 +++---- docs/setup.md | 56 +++++++++++++-------------------- 5 files changed, 41 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 9f275e74..e2576e0c 100644 --- a/README.md +++ b/README.md @@ -80,14 +80,13 @@ npx @waishnav/devspace init During setup, DevSpace asks for: +- where you will use it: ChatGPT, Coding Agents, or both - the local project folders DevSpace is allowed to open -- the local port, usually `7676` -- whether a remote MCP host and/or local coding harness will use DevSpace -- which subagent providers DevSpace may launch +- which Coding Agents DevSpace may use -If a remote MCP host will connect, setup also asks for your public HTTPS base +If you select ChatGPT, setup also asks for your public HTTPS base URL from Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or another reverse -proxy. Local-harness-only setups do not need a tunnel or public URL. +proxy. A Coding Agents-only setup does not need a tunnel or public URL. Use the public origin without `/mcp` during setup: @@ -96,9 +95,8 @@ https://your-tunnel-host.example.com ``` You will configure your MCP client with the public `/mcp` URL after setup. -Run `devspace serve` when using the MCP server. For a local coding harness, -setup prints a `skills` command that installs DevSpace's Subagents skill into -the harnesses you choose; DevSpace does not write into their skill directories. +Run `devspace serve` when using ChatGPT. For Coding Agents, setup prints a +`skills` command and lets the Skills CLI handle installation. When the client connects, DevSpace opens an Owner password approval page. Enter the Owner password printed by `devspace init`. It is also stored in: diff --git a/docs/chatgpt-coding-workflow.md b/docs/chatgpt-coding-workflow.md index 90d53180..d7a5d13c 100644 --- a/docs/chatgpt-coding-workflow.md +++ b/docs/chatgpt-coding-workflow.md @@ -116,7 +116,7 @@ DevSpace discovers standard Agent Skills from: It also keeps compatibility with: -- the bundled `subagent-delegation` skill when Subagents are enabled, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists +- the bundled `subagents` skill when Subagents are enabled, unless `~/.devspace/skills/subagents/SKILL.md` exists - `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills` - additional paths from `DEVSPACE_SKILL_PATHS` @@ -142,7 +142,7 @@ Skill paths may be outside the workspace. DevSpace only permits reading: Set `DEVSPACE_SKILLS=0` to hide skills from workspace output. Enable Subagents and choose providers through `devspace init` or the persisted provider -configuration. The bundled `subagent-delegation` skill teaches the minimal +configuration. The bundled `subagents` skill teaches the minimal `devspace agents targets`, `devspace agents ls`, `devspace agents run`, `devspace agents continue`, and `devspace agents show` workflow. The catalog comes from `open_workspace`; `devspace agents ls` lists existing subagent diff --git a/docs/configuration.md b/docs/configuration.md index 5aa7b3e2..56e1b204 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -136,7 +136,7 @@ DevSpace discovers standard Agent Skills from: It also keeps compatibility with: -- the bundled `subagent-delegation` skill when Subagents are enabled, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists +- the bundled `subagents` skill when Subagents are enabled, unless `~/.devspace/skills/subagents/SKILL.md` exists - `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills` - additional paths from `DEVSPACE_SKILL_PATHS` @@ -185,17 +185,17 @@ descriptions, providers, and optional models/effort levels so the host model can agent without reading provider-specific launch details. Disabled or unavailable providers and their profiles are omitted from this model-facing catalog. `devspace agents ls` lists existing subagent sessions for the current workspace, scoped by the -workspace environment injected into shell commands. The `subagent-delegation` +workspace environment injected into shell commands. The `subagents` skill teaches the model to use only the minimal `devspace agents ls`, `devspace agents targets`, `devspace agents run`, `devspace agents continue`, and `devspace agents show` workflow. -For Codex, Claude Code, OpenCode, Pi, or another supported local harness, use +For Codex, Claude Code, OpenCode, Pi, or another supported Coding Agent, use the Skills CLI to install the same skill. DevSpace setup prints this command but -does not run it or write into harness directories: +does not run it or write into agent skill directories: ```bash -npx skills add Waishnav/devspace --skill subagent-delegation --global +npx skills add Waishnav/devspace --skill subagents --global ``` Starter profile templates are available under `examples/agents/`. Copy or adapt diff --git a/docs/gotchas.md b/docs/gotchas.md index f9412440..3cccca40 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -216,14 +216,14 @@ DevSpace looks in standard Agent Skills locations: It also checks compatibility and custom paths: -- the bundled `subagent-delegation` skill when Subagents are enabled, unless `~/.devspace/skills/subagent-delegation/SKILL.md` exists +- the bundled `subagents` skill when Subagents are enabled, unless `~/.devspace/skills/subagents/SKILL.md` exists - `DEVSPACE_AGENT_DIR/skills`, defaulting to `~/.codex/skills` - additional paths from `DEVSPACE_SKILL_PATHS` When Subagents are enabled, DevSpace loads agent profiles from `~/.devspace/agents/*.md` and project `.devspace/agents/*.md`, then exposes a compact profile catalog through `open_workspace`. The bundled -`subagent-delegation` skill keeps the model-facing workflow to +`subagents` skill keeps the model-facing workflow to `devspace agents targets`, `devspace agents ls`, `devspace agents run`, `devspace agents continue`, and `devspace agents show`. Those commands automatically manage the internal local agent daemon; `devspace @@ -231,15 +231,15 @@ serve` is not a prerequisite. `devspace agents ls` lists existing subagent sessions, not profile definitions. -For a local coding harness, run the installation command printed by +For a Coding Agent, run the installation command printed by `devspace init`: ```bash -npx skills add Waishnav/devspace --skill subagent-delegation --global +npx skills add Waishnav/devspace --skill subagents --global ``` -The Skills CLI handles harness discovery and installation. DevSpace setup does -not copy files into harness skill directories. +The Skills CLI handles agent discovery and installation. DevSpace setup does +not copy files into agent skill directories. Packaged agent profile examples under `examples/agents/` are starter templates. Copy or adapt them into one of the active profile directories before use. diff --git a/docs/setup.md b/docs/setup.md index 7d5d5399..9f2d9d32 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -1,7 +1,6 @@ # Setup Guide -This guide covers both remote MCP hosts and local coding harnesses using -DevSpace in local projects. +This guide covers ChatGPT and Coding Agents using DevSpace with local projects. ## Requirements @@ -9,10 +8,10 @@ DevSpace in local projects. - npm - Git - Bash, including Git Bash or WSL on Windows -- a public HTTPS URL that forwards to the local DevSpace server, only when a - remote MCP host will connect +- a public HTTPS URL that forwards to the local DevSpace server, only when + ChatGPT will connect -DevSpace does not create the public tunnel for you. Remote MCP users can use +DevSpace does not create the public tunnel for you. ChatGPT users can use Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or their own HTTPS reverse proxy. @@ -26,9 +25,12 @@ npx @waishnav/devspace init The setup flow asks one question at a time. -### Project Roots +First choose where you will use DevSpace: ChatGPT, Coding Agents, or both. +DevSpace uses that answer to skip setup that does not apply to you. -Choose the folders ChatGPT is allowed to open through DevSpace. Keep this +### Project roots + +Choose the project folders DevSpace can access. Keep this narrow. Examples: @@ -45,39 +47,26 @@ Examples: C:\Users\alice\dev,C:\Users\alice\work ``` -### Local Port - -The default is `7676`. - -The local MCP URL is: - -```text -http://127.0.0.1:7676/mcp -``` - -### Usage And Subagents +### Coding Agents -Setup asks independently whether a remote MCP host will connect and whether a -local coding harness will use DevSpace subagents. It then detects the supported -providers and asks which ones DevSpace may launch. These choices are persisted -as provider objects under `subagents` in `~/.devspace/config.json`. +Setup detects supported Coding Agents and asks which ones DevSpace may use. +These choices are stored as provider objects under `subagents` in +`~/.devspace/config.json`. -For a local harness, setup prints this command instead of modifying harness -directories itself: +If you selected Coding Agents, setup prints: ```bash -npx skills add Waishnav/devspace --skill subagent-delegation --global +npx skills add Waishnav/devspace --skill subagents --global ``` -The Skills CLI asks which installed harnesses should receive the skill. The -skill uses `devspace agents targets`, `run`, `continue`, `show`, and `ls`; these -commands start DevSpace's local agent daemon as needed and do not require -`devspace serve`. +The Skills CLI asks which installed Coding Agents should receive the skill. +The skill uses `devspace agents targets`, `run`, `continue`, `show`, and `ls`. +These commands do not require `devspace serve`. -### Public Base URL For Remote MCP +### Connect ChatGPT -Start your tunnel or reverse proxy before entering this value. Point the tunnel -at: +Setup only asks for a public URL if you selected ChatGPT. Start your tunnel or +reverse proxy first and point it at: ```text http://127.0.0.1:7676 @@ -95,8 +84,7 @@ Configure the MCP client with the full MCP endpoint: https://your-tunnel-host.example.com/mcp ``` -Skip remote MCP access during setup for a local-harness-only configuration; no -public URL is required. +A Coding Agents-only setup skips this section. ## Start The Server From 5576cc30a94d645da9f1c27d61482f5963915497 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 19:00:52 +0530 Subject: [PATCH 07/13] fix(init): preserve existing configuration --- src/cli.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cli.ts b/src/cli.ts index 408142cb..41e359f0 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -208,6 +208,7 @@ async function runInit({ force }: { force: boolean }): Promise { ); const config: DevspaceUserConfig = { + ...files.config, host: files.config.host ?? "127.0.0.1", port, allowedRoots, From 3898b37d0d671e37d33b474cd10edc74513636e2 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 19:01:30 +0530 Subject: [PATCH 08/13] fix(skills): support npx-only installs --- skills/subagents/SKILL.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/skills/subagents/SKILL.md b/skills/subagents/SKILL.md index 65ed8361..521ab39f 100644 --- a/skills/subagents/SKILL.md +++ b/skills/subagents/SKILL.md @@ -14,19 +14,21 @@ being used. ## Core commands -Use only these commands for normal delegation: +Use only these commands for normal delegation. The `npx` form works whether or +not the user installed DevSpace globally. ```bash -devspace agents targets -devspace agents ls -devspace agents run "" -devspace agents continue "" -devspace agents show +npx @waishnav/devspace agents targets +npx @waishnav/devspace agents ls +npx @waishnav/devspace agents run "" +npx @waishnav/devspace agents continue "" +npx @waishnav/devspace agents show ``` `targets` shows the providers and profiles available for the current project. Use an agent or profile already presented by DevSpace. If you do not know which -ones are available, run `devspace agents targets` before delegating. +ones are available, run `npx @waishnav/devspace agents targets` before +delegating. `ls` shows existing subagent sessions for the current project. DevSpace selects the project from the command environment. Use the returned `agt_...` ID with @@ -44,8 +46,8 @@ profile is needed. Run `targets` if you do not know which providers are enabled. Continuation supports the same per-turn model and effort overrides: ```bash -devspace agents continue --model "" -devspace agents continue --effort "" +npx @waishnav/devspace agents continue --model "" +npx @waishnav/devspace agents continue --effort "" ``` `show ` prints status and the latest response. If the agent is still @@ -58,8 +60,8 @@ directly. DevSpace manages execution and continuation for you. ## Choosing a profile Choose from the profiles DevSpace has already presented. If no catalog is -visible, run `devspace agents targets`. Use the profile name with -`devspace agents run`. If no profile fits, use an enabled provider from the +visible, run `npx @waishnav/devspace agents targets`. Use the profile name with +the `agents run` command. If no profile fits, use an enabled provider from the same result. Profiles may declare a model and optional effort level. To override the @@ -67,8 +69,8 @@ configured/default provider model or effort level for a run, pass `--model` or `--effort`: ```bash -devspace agents run --model "" -devspace agents run --effort "" +npx @waishnav/devspace agents run --model "" +npx @waishnav/devspace agents run --effort "" ``` Use `--effort` only when the user asks for a specific reasoning depth or when From 75c1643b3e5d774929dd4bd279819e40b71f492d Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 19:24:17 +0530 Subject: [PATCH 09/13] cleanup --- skills/subagents/SKILL.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/skills/subagents/SKILL.md b/skills/subagents/SKILL.md index 521ab39f..e2869fde 100644 --- a/skills/subagents/SKILL.md +++ b/skills/subagents/SKILL.md @@ -18,16 +18,16 @@ Use only these commands for normal delegation. The `npx` form works whether or not the user installed DevSpace globally. ```bash -npx @waishnav/devspace agents targets -npx @waishnav/devspace agents ls -npx @waishnav/devspace agents run "" -npx @waishnav/devspace agents continue "" -npx @waishnav/devspace agents show +devspace agents targets +devspace agents ls +devspace agents run "" +devspace agents continue "" +devspace agents show ``` `targets` shows the providers and profiles available for the current project. Use an agent or profile already presented by DevSpace. If you do not know which -ones are available, run `npx @waishnav/devspace agents targets` before +ones are available, run `devspace agents targets` before delegating. `ls` shows existing subagent sessions for the current project. DevSpace selects @@ -46,8 +46,8 @@ profile is needed. Run `targets` if you do not know which providers are enabled. Continuation supports the same per-turn model and effort overrides: ```bash -npx @waishnav/devspace agents continue --model "" -npx @waishnav/devspace agents continue --effort "" +devspace agents continue --model "" +devspace agents continue --effort "" ``` `show ` prints status and the latest response. If the agent is still @@ -60,7 +60,7 @@ directly. DevSpace manages execution and continuation for you. ## Choosing a profile Choose from the profiles DevSpace has already presented. If no catalog is -visible, run `npx @waishnav/devspace agents targets`. Use the profile name with +visible, run `devspace agents targets`. Use the profile name with the `agents run` command. If no profile fits, use an enabled provider from the same result. @@ -69,8 +69,8 @@ configured/default provider model or effort level for a run, pass `--model` or `--effort`: ```bash -npx @waishnav/devspace agents run --model "" -npx @waishnav/devspace agents run --effort "" +devspace agents run --model "" +devspace agents run --effort "" ``` Use `--effort` only when the user asks for a specific reasoning depth or when From d99188d3f385bd978cab2c0ed792d603c3e77d98 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 19:55:52 +0530 Subject: [PATCH 10/13] fix(init): skip MCP roots for local-only setup --- src/cli.ts | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 41e359f0..4c15a0a5 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -102,7 +102,7 @@ async function ensureConfigured(): Promise { "Run:", " devspace init", "", - "Or provide DEVSPACE_OAUTH_OWNER_TOKEN and DEVSPACE_ALLOWED_ROOTS.", + "Or provide DEVSPACE_OAUTH_OWNER_TOKEN.", ].join("\n"), ); } @@ -143,17 +143,20 @@ async function runInit({ force }: { force: boolean }): Promise { const useChatGpt = usesChatGpt(usage); const useCodingAgents = usesCodingAgents(usage); - const defaultRoots = files.config.allowedRoots?.join(", ") || process.cwd(); - const rootsAnswer = await textPrompt({ - message: `Which project folders can DevSpace access? Press Enter to use ${defaultRoots}`, - placeholder: defaultRoots, - defaultValue: defaultRoots, - validate: (value) => value?.trim() ? undefined : "Enter at least one project root.", - }); - const allowedRoots = rootsAnswer - .split(",") - .map((root) => resolve(expandHomePath(root.trim()))) - .filter(Boolean); + let allowedRoots: string[] | undefined; + if (useChatGpt) { + const defaultRoots = files.config.allowedRoots?.join(", ") || process.cwd(); + const rootsAnswer = await textPrompt({ + message: `Which project folders can DevSpace access? Press Enter to use ${defaultRoots}`, + placeholder: defaultRoots, + defaultValue: defaultRoots, + validate: (value) => value?.trim() ? undefined : "Enter at least one project root.", + }); + allowedRoots = rootsAnswer + .split(",") + .map((root) => resolve(expandHomePath(root.trim()))) + .filter(Boolean); + } const port = isValidPort(files.config.port) ? files.config.port : 7676; @@ -211,7 +214,7 @@ async function runInit({ force }: { force: boolean }): Promise { ...files.config, host: files.config.host ?? "127.0.0.1", port, - allowedRoots, + ...(allowedRoots ? { allowedRoots } : {}), publicBaseUrl, subagents, }; @@ -223,7 +226,7 @@ async function runInit({ force }: { force: boolean }): Promise { writeDevspaceAuth(auth); const lines = [ - `Project folders: ${allowedRoots.join(", ")}`, + ...(allowedRoots ? [`Project folders: ${allowedRoots.join(", ")}`] : []), `Coding Agents: ${selectedProviders.join(", ")}`, ...(publicBaseUrl ? [`ChatGPT connection URL: ${publicBaseUrl}/mcp`] : []), ]; From 86d2400a6d2f536438ea1c0dfaa0a6fee444270a Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 19:55:52 +0530 Subject: [PATCH 11/13] docs(init): explain local project authority --- README.md | 9 +++++---- docs/gotchas.md | 6 ++++-- docs/setup.md | 9 +++++++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e2576e0c..b1e4f0a3 100644 --- a/README.md +++ b/README.md @@ -81,12 +81,13 @@ npx @waishnav/devspace init During setup, DevSpace asks for: - where you will use it: ChatGPT, Coding Agents, or both -- the local project folders DevSpace is allowed to open - which Coding Agents DevSpace may use -If you select ChatGPT, setup also asks for your public HTTPS base -URL from Cloudflare Tunnel, ngrok, Pinggy, Tailscale Funnel, or another reverse -proxy. A Coding Agents-only setup does not need a tunnel or public URL. +If you select ChatGPT, setup also asks which local project folders it may open +and for your public HTTPS base URL from Cloudflare Tunnel, ngrok, Pinggy, +Tailscale Funnel, or another reverse proxy. A Coding Agents-only setup asks +neither question: local commands use the current Git project, or the current +directory outside a repository. Use the public origin without `/mcp` during setup: diff --git a/docs/gotchas.md b/docs/gotchas.md index 3cccca40..495243bb 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -154,9 +154,11 @@ DevSpace does not currently prune workspace sessions, conversation bindings, or review refs. A future product retention policy will define safe cleanup for these records; no automatic deletion is performed today. -## Workspace Path Rejected +## MCP Workspace Path Rejected -The path must be inside one of the allowed roots configured during setup. +The path passed to `open_workspace` must be inside one of the allowed roots +configured during ChatGPT setup. Direct `devspace agents` commands instead use +the current local project and are not gated by MCP allowed roots. Run: diff --git a/docs/setup.md b/docs/setup.md index 9f2d9d32..934b0b8c 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -30,8 +30,8 @@ DevSpace uses that answer to skip setup that does not apply to you. ### Project roots -Choose the project folders DevSpace can access. Keep this -narrow. +If you selected ChatGPT, choose the project folders it may open through +DevSpace. Keep this narrow. Examples: @@ -47,6 +47,11 @@ Examples: C:\Users\alice\dev,C:\Users\alice\work ``` +A Coding Agents-only setup skips this question. Direct `devspace agents` +commands use the current Git project, or the current directory outside a +repository, with the authority of your local shell. MCP workspace operations +remain limited to the roots configured for ChatGPT. + ### Coding Agents Setup detects supported Coding Agents and asks which ones DevSpace may use. From dc31085542cd6303a7ebeef598166341a82477b7 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 20:26:11 +0530 Subject: [PATCH 12/13] docs(skills): focus subagents on capability usage --- skills/subagents/SKILL.md | 164 ++++++++++---------------------------- 1 file changed, 43 insertions(+), 121 deletions(-) diff --git a/skills/subagents/SKILL.md b/skills/subagents/SKILL.md index e2869fde..d01c544f 100644 --- a/skills/subagents/SKILL.md +++ b/skills/subagents/SKILL.md @@ -1,147 +1,69 @@ --- name: subagents -description: Delegate coding tasks to user-configured DevSpace subagents. +description: Delegate focused coding, research, review, or verification work to a bounded DevSpace subagent. Use when a task benefits from separate context, a specialist perspective, or a follow-up with the same worker. --- -# Subagents +# DevSpace subagents -Use this skill when the user explicitly asks to delegate work to another coding -agent, use a named subagent, get a second opinion, compare approaches, or run -a subagent-like workflow. +Use the DevSpace CLI through the host's shell or process tool. Run commands from +the project the subagent should work on. DevSpace scopes sessions to the host +workspace when supplied, otherwise to the current Git repository or project +directory. -Do not use subagents silently. Tell the user when another subagent is -being used. +## Choose a target -## Core commands - -Use only these commands for normal delegation. The `npx` form works whether or -not the user installed DevSpace globally. +Discover usable targets instead of guessing names: ```bash -devspace agents targets -devspace agents ls -devspace agents run "" -devspace agents continue "" -devspace agents show +devspace agents targets --json ``` -`targets` shows the providers and profiles available for the current project. -Use an agent or profile already presented by DevSpace. If you do not know which -ones are available, run `devspace agents targets` before -delegating. - -`ls` shows existing subagent sessions for the current project. DevSpace selects -the project from the command environment. Use the returned `agt_...` ID with -`continue`. Provider session IDs cannot replace DevSpace agent IDs. +Configured profiles include a description and may define provider, model, +effort, and task instructions. Choose a matching profile when one fits. Use a +provider target when no profile fits or a specific provider is needed. +Unavailable and disabled providers are omitted. -`run ""` starts a new configured profile and prints a -DevSpace agent id. +Usually rely on the target's configured model and effort. Pass `--model` or +`--effort` only with a value supported by that provider. DevSpace passes these +values through without translating them between providers. -`run ""` starts an enabled provider when no configured -profile is needed. Run `targets` if you do not know which providers are enabled. +## Start work -`continue ""` sends a follow-up to an existing agent. Do not use -`run ` for continuation. - -Continuation supports the same per-turn model and effort overrides: +Give the subagent a self-contained brief. Include the objective, relevant +paths, constraints, decisions it needs from the current conversation, and the +expected result. The subagent receives the brief and its profile instructions, +not the parent conversation. ```bash -devspace agents continue --model "" -devspace agents continue --effort "" +devspace agents run "" --json +devspace agents run --model --effort "" --json ``` -`show ` prints status and the latest response. If the agent is still -running, `show` waits briefly. If there is still no final response, call `show` -again later. - -Use DevSpace commands for delegation instead of calling provider commands -directly. DevSpace manages execution and continuation for you. +The result contains a DevSpace agent `id` and its current status. Execution +continues independently, so retain the ID for later inspection or follow-up. -## Choosing a profile - -Choose from the profiles DevSpace has already presented. If no catalog is -visible, run `devspace agents targets`. Use the profile name with -the `agents run` command. If no profile fits, use an enabled provider from the -same result. - -Profiles may declare a model and optional effort level. To override the -configured/default provider model or effort level for a run, pass `--model` -or `--effort`: +## Inspect and continue ```bash -devspace agents run --model "" -devspace agents run --effort "" +devspace agents show --json +devspace agents continue "" --json +devspace agents ls --json ``` -Use `--effort` only when the user asks for a specific reasoning depth or when -the task clearly needs a different effort than the configured profile default. -Effort values are provider-specific. Use a value supported by the selected -provider. DevSpace does not translate values between providers. - -Good delegation targets: - -- `reviewer`: second opinion, bug risk, security risk, test gaps. -- `explorer`: read-only codebase investigation. -- `implementer`: focused implementation when the user asked for delegation. - -Do not delegate ordinary coding work just because a profile exists. Use normal -DevSpace tools unless the user asked for delegation, another agent's opinion, -parallel work, or a named subagent. - -## Worker prompts - -Agents start with only the prompt you send plus their configured profile -instructions. Make prompts self-contained. - -Implementation prompt shape: - -```text -Goal: - - -Context: - +- `show` waits briefly for active work, then returns the current status and any + available response or error. +- `continue` gives the same subagent another turn with its existing provider + session and context. +- `ls` returns sessions belonging to the current project. -Relevant files: - +Call `show --json` again later while the status is `starting` or `running`. +`idle` means the response is ready. `error` and `stopped` are terminal without +a successful response. Continue an agent when its existing context is useful; +start another agent for unrelated work. -Acceptance criteria: -- - -Rules: -- Keep changes focused. -- Do not perform unrelated refactors. -- Report blockers clearly. -``` - -Read-only investigation prompt shape: - -```text -Question: - - -Scope: - - -Rules: -- Do not modify files. -- Cite relevant file paths and symbols. -- Separate facts from guesses. -``` - -## After the worker responds - -Always review the result before presenting it as verified. - -For write-capable tasks, inspect changed files and run or explain relevant -tests. For read-only tasks, verify that important claims are supported by repo -evidence. - -Be transparent in the final response: - -```text -I used . It reported . I verified . Remaining risk: -. -``` +## Good uses -Never hide that a subagent was used. +- Review a change for correctness, security, or missing tests. +- Investigate a bounded part of a codebase and report findings. +- Implement one isolated change with clear acceptance criteria. +- Run a focused verification pass after other work. From 77f4eaaa9093da6a094b429797c7950d0e71588f Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Thu, 20 Aug 2026 20:46:28 +0530 Subject: [PATCH 13/13] cleanup in skills and onboarding leakage --- skills/subagents/SKILL.md | 29 +++++++--------------------- src/local-agent-availability.test.ts | 6 +++--- src/local-agent-availability.ts | 2 +- src/server.test.ts | 2 +- 4 files changed, 12 insertions(+), 27 deletions(-) diff --git a/skills/subagents/SKILL.md b/skills/subagents/SKILL.md index d01c544f..b799ade2 100644 --- a/skills/subagents/SKILL.md +++ b/skills/subagents/SKILL.md @@ -5,10 +5,7 @@ description: Delegate focused coding, research, review, or verification work to # DevSpace subagents -Use the DevSpace CLI through the host's shell or process tool. Run commands from -the project the subagent should work on. DevSpace scopes sessions to the host -workspace when supplied, otherwise to the current Git repository or project -directory. +Use the DevSpace CLI through the shell or process tool. Run commands from the project the subagent should work on. ## Choose a target @@ -18,29 +15,20 @@ Discover usable targets instead of guessing names: devspace agents targets --json ``` -Configured profiles include a description and may define provider, model, -effort, and task instructions. Choose a matching profile when one fits. Use a -provider target when no profile fits or a specific provider is needed. -Unavailable and disabled providers are omitted. +Configured profiles include a description and may define provider, model, effort, and task instructions. Choose a matching profile when one fits. Use a provider target when no profile fits or a specific provider is needed. -Usually rely on the target's configured model and effort. Pass `--model` or -`--effort` only with a value supported by that provider. DevSpace passes these -values through without translating them between providers. +Usually rely on the target's configured model and effort. Pass `--model` or `--effort` only with a value supported by that provider. DevSpace passes these values through without translating them between providers. ## Start work -Give the subagent a self-contained brief. Include the objective, relevant -paths, constraints, decisions it needs from the current conversation, and the -expected result. The subagent receives the brief and its profile instructions, -not the parent conversation. +Give the subagent a self-contained brief. Include the objective, relevant paths, constraints, decisions it needs from the current conversation, and the expected result. The subagent receives the brief and its profile instructions, not the parent conversation. ```bash devspace agents run "" --json devspace agents run --model --effort "" --json ``` -The result contains a DevSpace agent `id` and its current status. Execution -continues independently, so retain the ID for later inspection or follow-up. +The result contains a DevSpace agent `id` and its current status. Execution continues independently, so retain the ID for later inspection or follow-up. ## Inspect and continue @@ -56,14 +44,11 @@ devspace agents ls --json session and context. - `ls` returns sessions belonging to the current project. -Call `show --json` again later while the status is `starting` or `running`. -`idle` means the response is ready. `error` and `stopped` are terminal without -a successful response. Continue an agent when its existing context is useful; -start another agent for unrelated work. +Call `show --json` again later while the status is `starting` or `running`. `idle` means the response is ready. `error` and `stopped` are terminal without a successful response. Continue an agent when its existing context is useful; start another agent for unrelated work. ## Good uses - Review a change for correctness, security, or missing tests. - Investigate a bounded part of a codebase and report findings. - Implement one isolated change with clear acceptance criteria. -- Run a focused verification pass after other work. +- Run a focused verification pass after other work. \ No newline at end of file diff --git a/src/local-agent-availability.test.ts b/src/local-agent-availability.test.ts index 9690843a..3dcf4ba6 100644 --- a/src/local-agent-availability.test.ts +++ b/src/local-agent-availability.test.ts @@ -10,7 +10,7 @@ import { assert.equal(availability.name, "codex"); assert.equal(typeof availability.available, "boolean"); if (availability.available) { - assert.match(availability.note ?? "", /app-server support is verified on first run/); + assert.equal(availability.note, "available"); } } @@ -41,8 +41,8 @@ import { assert.equal( formatLocalAgentProviderAvailabilitySummary([ - { name: "codex", available: true, note: "executable detected; app-server support is verified on first run" }, + { name: "codex", available: true, note: "available" }, { name: "pi", available: false, reason: "pi executable not found" }, ]), - "available: codex (executable detected; app-server support is verified on first run); unavailable: pi (pi executable not found)", + "available: codex (available); unavailable: pi (pi executable not found)", ); diff --git a/src/local-agent-availability.ts b/src/local-agent-availability.ts index 9064aa21..2c8dd6e1 100644 --- a/src/local-agent-availability.ts +++ b/src/local-agent-availability.ts @@ -85,7 +85,7 @@ function codexAvailability(env: NodeJS.ProcessEnv): LocalAgentProviderAvailabili return availability.available ? { ...availability, - note: "executable detected; app-server support is verified on first run", + note: "available", } : availability; } diff --git a/src/server.test.ts b/src/server.test.ts index 8266a0fd..cb29d11c 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -20,7 +20,7 @@ import { WorkspaceRegistry } from "./workspaces.js"; const execFileAsync = promisify(execFile); test("open_workspace keeps lifecycle flags out of model output and preserves complete card metadata", async (t) => { - const providerNote = "app-server support is verified on first run"; + const providerNote = "available"; const context = await fixture(t, { localAgentProviders: [{ name: "codex", available: true, note: providerNote }], });