Skip to content
Open
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
9 changes: 5 additions & 4 deletions docs/artifact-exchange.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ directly into an open workspace. Enable the tool with

```text
open_workspace
-> download_artifact({ file, workspaceId, path })
-> download_artifact({ file, workspace_id, path })
-> { path }
```

1. Open the project with `open_workspace`.
2. Pass the host-provided native `file`, the returned `workspaceId`, and an
unused workspace-relative `path` to `download_artifact`.
2. Pass the host-provided native `file`, the returned `workspaceId` as
`workspace_id`, and an unused workspace-relative `path` to
`download_artifact`.
3. Use the returned path with the ordinary DevSpace filesystem tools.

```text
download_artifact({
file: <native file value supplied by the MCP host>,
workspaceId: "ws_123",
workspace_id: "ws_123",
path: "public/images/generated-image.png"
})
```
Expand Down
16 changes: 8 additions & 8 deletions docs/chatgpt-coding-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ ChatGPT should call `open_workspace` once for a project folder:
```

The result includes a `workspaceId`. All later file, search, edit, show-changes,
and shell calls should reuse that same `workspaceId`.
and shell calls should pass that same value as `workspace_id`.

ChatGPT may support automatic checkout recovery through optional host
conversation metadata. This is an OpenAI-host adapter detail, not a standard MCP
conversation field. When that optional context is available, opening the same
checkout project again in the same conversation can continue in the existing
workspace, and the context already provided for that reused checkout is not
repeated. The portable workflow remains the same: keep using the `workspaceId`
returned by `open_workspace` for later operations. Hosts without supported
conversation context receive a normal new workspace and continue with that
explicit `workspaceId` workflow.
returned by `open_workspace` as `workspace_id` for later operations. Hosts
without supported conversation context receive a normal new workspace and
continue with that explicit workspace ID workflow.
The model receives actionable workspace instructions; automatic-reuse
bookkeeping is not a model-facing choice.

Expand Down Expand Up @@ -78,12 +78,12 @@ Managed worktrees are created under:
```

Worktree mode requires a Git repository with at least one commit. It starts from
`HEAD` unless `baseRef` is provided.
`HEAD` unless `base_ref` is provided.

Each worktree-mode call creates a new managed worktree and returns a new
`workspaceId`. Reuse that ID for work inside that worktree; call
`open_workspace` in worktree mode again only when another isolated worktree is
actually required.
`workspaceId`. Reuse that ID as `workspace_id` for work inside that worktree;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wtf? why instructions are written as if they are trying to make it backward compatible?

call `open_workspace` in worktree mode again only when another isolated worktree
is actually required.

Uncommitted source checkout changes are not copied into the managed worktree.
DevSpace reports when the source checkout was dirty so the model can decide how
Expand Down
7 changes: 4 additions & 3 deletions docs/gotchas.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,9 @@ the same project in that conversation; repeated opens reuse the `workspaceId`
and do not repeat context already provided for that reused checkout. Worktree
mode always creates a new isolated workspace with its own complete context.
Hosts without supported conversation metadata receive a normal new workspace.
In all cases, continue passing the `workspaceId` returned by `open_workspace` to
later tools. Other MCP hosts use this explicit workspace workflow as well.
In all cases, continue passing the `workspaceId` returned by `open_workspace` as
`workspace_id` to later tools. Other MCP hosts use this explicit workspace
workflow as well.

To review work, call `show_changes` once after the final related file change. It
shows the combined changes and advances the review point automatically.
Expand Down Expand Up @@ -186,7 +187,7 @@ Worktree mode requires:
- Git installed
- the path is inside a Git repository
- the repository has at least one commit
- the requested `baseRef` resolves to a commit
- the requested `base_ref` resolves to a commit

For a new repository, create the first commit or use checkout mode.

Expand Down
6 changes: 3 additions & 3 deletions docs/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ sessions.

Native file download is an opt-in, one-shot transfer into an already-open
workspace. `download_artifact` accepts the MCP host's native file value, the
`workspaceId` returned by `open_workspace`, and an unused relative destination
path. It returns only the workspace-relative path and does not create a
persistent artifact service or reusable artifact ID.
`workspace_id` containing the `workspaceId` returned by `open_workspace`, and an
unused relative destination path. It returns only the workspace-relative path
and does not create a persistent artifact service or reusable artifact ID.

DevSpace accepts only the documented native-file object and trusted OpenAI
download hosts and redirects. Arbitrary URL strings, local source paths,
Expand Down
4 changes: 2 additions & 2 deletions src/artifact-download.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function testOneToolContract(): void {
const descriptor = registered.get("download_artifact")?.descriptor;
assert.ok(descriptor);
assert.deepEqual(descriptor._meta, { "openai/fileParams": ["file"] });
assert.deepEqual(Object.keys(descriptor.inputSchema as object).sort(), ["file", "path", "workspaceId"]);
assert.deepEqual(Object.keys(descriptor.inputSchema as object).sort(), ["file", "path", "workspace_id"]);
assert.deepEqual(Object.keys(descriptor.outputSchema as object), ["path"]);
assert.equal((descriptor.annotations as { destructiveHint?: boolean }).destructiveHint, false);

Expand Down Expand Up @@ -353,7 +353,7 @@ function testLogRedaction(): void {
file_name: "generated.png",
authorization: "Bearer log-secret",
},
workspaceId: "ws_secret",
workspace_id: "ws_secret",
path: "private/generated.png",
});
const serialized = JSON.stringify(fields);
Expand Down
8 changes: 4 additions & 4 deletions src/artifact-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ export function registerArtifactTools(
file: openAIFileReferenceInputSchema.describe(
"Native file value authorized and supplied by the MCP host.",
),
workspaceId: z.string().min(1).describe(
"Workspace to use. Reuse the current project's workspaceId.",
workspace_id: z.string().min(1).describe(
"Workspace to use. Pass the workspaceId returned by open_workspace as workspace_id.",
),
path: z.string().min(1).describe(
"Relative destination path inside the selected workspace. The destination must not already exist.",
Expand All @@ -117,7 +117,7 @@ export function registerArtifactTools(
annotations: ARTIFACT_WRITE_ANNOTATIONS,
},
async (input) => executeArtifactTool(config, input, async () => {
const workspace = workspaces.getWorkspace(input.workspaceId);
const workspace = workspaces.getWorkspace(input.workspace_id);
const downloaded = await downloadIncomingArtifact({
registry: incomingRegistry,
workspaceId: workspace.id,
Expand Down Expand Up @@ -292,7 +292,7 @@ export function artifactToolLogFields(
fileProvided: input.file !== undefined,
fileReferenceShape: describeIncomingArtifactValue(input.file),
downloadUrlHostname: incomingFileDownloadHostname(input.file),
workspaceId: input.workspaceId,
workspaceId: input.workspace_id,
path: input.path,
};
}
Expand Down
Loading
Loading