Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions docs/platform/chatgpt-app-privacy-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Vulca ChatGPT App Privacy Policy

**Effective date:** 2026-05-07

This policy describes the data practices for the submitted Vulca ChatGPT App
remote profile. Vulca is an agent-native visual workflow tool for tradition
lookup, visual direction support, prompt composition, and rubric-based visual
evaluation.

This policy is scoped to the ChatGPT App remote MCP profile. The open-source
Vulca Python package, local CLI, local MCP server, and separately configured
provider-backed workflows may have different data flows depending on how a user
runs them.

## App Scope

The submitted ChatGPT App profile exposes only these tools:

- `list_traditions`
- `get_tradition_guide`
- `search_traditions`
- `compose_prompt_from_design`
- `evaluate_artwork`

The submitted profile does not expose image generation, image upload, pixel
reading, redraw, inpaint, layer mutation, publishing, archive, sync, admin, or
filesystem-writing tools.

`evaluate_artwork` is configured in `rubric_only` and `mock` mode for this
profile. It returns an L1-L5 rubric payload and does not read image pixels or
call a vision model by default.

## Data We Receive

Vulca receives only the tool arguments that ChatGPT sends to the selected MCP
tool. Depending on the tool, this can include:

- Tradition names, such as `chinese_xieyi` or `photography`.
- Search tags or short visual keywords supplied by the user.
- A task-specific intent or evaluation description supplied by the user.
- A workspace-relative design document path for `compose_prompt_from_design`.
- The text content of an approved `design.md` file when prompt composition is
requested and the file is inside the configured remote workspace root.
- An image reference string for `evaluate_artwork`; in the submitted profile,
this is used only as an input placeholder for rubric selection and is not
opened, uploaded, or returned.
- Basic transport and security information generated by the hosting
environment, such as request time, IP address, user agent, status code, and
error summaries, if operational logging is enabled.
- Contact information that a user voluntarily provides when asking for support.

The submitted profile does not intentionally request or collect precise
location, payment card data, government identifiers, health information,
passwords, API keys, MFA codes, OAuth tokens, raw full chat history, or images.

## Data We Return To ChatGPT

Tool responses are purpose-limited to the user's request. Responses can include:

- The list of supported Vulca traditions and their public L1-L5 weights.
- Public tradition guide content, including terminology, taboos, weights, and
suggested layer structures.
- Ranked tradition search matches and matched public terms.
- A composed prompt, negative prompt, tradition tokens, color tokens, and style
treatment derived from a user-approved design document.
- A rubric-only L1-L5 evaluation structure, including the selected tradition,
rubric fields, score schema, and summary fields.

The submitted remote profile is designed not to return local filesystem paths,
raw image bytes, provider API responses, request IDs, trace IDs, session IDs,
authentication secrets, or internal debug payloads.

## Purposes Of Use

Vulca uses the data described above to:

- Provide the requested tradition lookup, search, prompt composition, or rubric
evaluation result.
- Validate that file paths remain inside the configured remote workspace root.
- Maintain app security, reliability, abuse prevention, and operational
debugging.
- Respond to support, privacy, or deletion requests.
- Comply with legal, platform, and app-review requirements.

Vulca does not sell personal data. Vulca does not use ChatGPT App tool inputs
for advertising or behavioral profiling.

## Recipients And Service Providers

For the submitted ChatGPT App profile, data may be processed by:

- OpenAI and ChatGPT as the platform through which the user invokes the app,
under OpenAI's applicable terms and privacy policy.
- Vulca's app server or hosting provider, for routing MCP requests and
returning tool responses.
- Operational service providers used for security, uptime monitoring, error
logging, or support, if configured.

The submitted profile does not send prompts, images, masks, files, or evaluation
requests to image-generation providers or third-party vision model providers.
If a user separately installs or runs Vulca outside this submitted profile and
explicitly configures provider-backed generation, editing, or VLM evaluation,
the selected provider may receive the prompts, images, masks, metadata, or
other inputs required for that separate workflow. Those separate workflows are
outside the submitted ChatGPT App remote profile.

## Retention

By default, the submitted profile does not persist raw tool inputs, full tool
outputs, design document contents, or image references after the request is
served.

Operational logs, if enabled by the production hosting environment, should be
limited to security and reliability data and retained for no longer than 30
days unless a longer period is required to investigate abuse, debug a user
reported issue, comply with law, or preserve service integrity.

Support emails and privacy requests are retained only as long as needed to
respond, maintain records of the request, and meet legal or platform
obligations.

## User Controls

Users can control what Vulca receives by choosing whether to invoke the app and
what information to include in their prompt or tool request.

Users should not provide sensitive personal data, secrets, precise location,
payment information, health information, government identifiers, or private
images to the submitted ChatGPT App profile.

Users can:

- Disconnect or disable the Vulca app from ChatGPT.
- Avoid sending personal information in visual keywords, intents, or design
documents.
- Request access, correction, deletion, or other privacy assistance by
contacting the maintainer.

## Security Measures

The submitted profile uses a positive allowlist of remote-safe tools. File reads
for prompt composition are constrained to `VULCA_REMOTE_WORKSPACE_ROOT`, and
paths outside that root are rejected. Cost-incurring, filesystem-writing,
image-generation, redraw, inpaint, archive, sync, and admin tools are not
exposed in the submitted profile.

Tool responses are minimized to remove local file paths and diagnostic metadata
that are not necessary for the user's request.

## Children's Privacy

The app is intended for general audiences and does not intentionally target
children under 13. Users should not submit children's personal data to the app.

## Changes To This Policy

This policy may be updated as the app changes. Material changes should be
reflected in the app submission metadata and resubmitted for review when
required by the platform.

## Contact

For privacy requests or support, contact:

Yu Haorui
Email: `yuhaorui48@gmail.com`
91 changes: 91 additions & 0 deletions docs/platform/chatgpt-app-resubmission-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# ChatGPT App Resubmission Checklist

**Status:** Privacy-remediation checklist
**Created:** 2026-05-07

## Rejection Reason

OpenAI review rejected Vulca because the submitted privacy policy did not
clearly disclose all data uses. The requested remediation is a complete policy
covering data collected, purposes, recipients, retention, and user controls, and
alignment with current tool inputs and outputs.

Relevant OpenAI requirements:

- ChatGPT app submissions must include a clear, published privacy policy.
- The policy must cover categories of personal data collected, purposes of use,
recipient categories, retention timelines, and user controls.
- Tool responses should return only data directly relevant to the request and
avoid diagnostic, telemetry, or internal identifiers unless required.
- MCP tool responses should be audited for nested fields, debug payloads, PII,
telemetry, internal IDs, and secrets.

## Code/Docs Remediation

- Publish `docs/platform/chatgpt-app-privacy-policy.md` at a stable public URL,
for example:
`https://github.com/vulca-org/vulca/blob/master/docs/platform/chatgpt-app-privacy-policy.md`
- Keep the submitted remote profile limited to:
- `list_traditions`
- `get_tradition_guide`
- `search_traditions`
- `compose_prompt_from_design`
- `evaluate_artwork`
- Confirm `compose_prompt_from_design` does not echo `source_design_path`.
- Confirm remote `evaluate_artwork` does not echo `image_path` or `latency_ms`.
- Re-run remote-profile tests before resubmission.

## Tool Response Audit

Run representative tool calls in ChatGPT developer mode or via MCP/API
Playground and record the raw responses.

Check that responses do not include:

- local filesystem paths;
- raw image bytes;
- full chat transcripts;
- precise location;
- API keys, OAuth tokens, passwords, or other secrets;
- request IDs, trace IDs, session IDs, internal account IDs;
- timestamps or latency diagnostics;
- unrelated debug payloads;
- provider raw responses.

Expected allowed response categories:

- public tradition identifiers and L1-L5 weights;
- public tradition guide content;
- user-supplied search tags echoed as `query_tags`;
- composed prompt fields derived from a user-approved design document;
- rubric-only L1-L5 evaluation payload.

## Dashboard Resubmission Notes

Use a concise release note:

```text
Privacy remediation after review feedback. Published a complete Vulca ChatGPT App privacy policy covering collected data, purposes, recipient categories, retention, and user controls. Audited remote MCP tool responses and removed unnecessary local path and diagnostic metadata from the submitted remote profile.
```

## Optional Email Reply

```text
Hello OpenAI review team,

Thank you for the review. We have remediated the privacy-policy issue for Vulca.

Changes made:
- Published a complete privacy policy covering data collected, purposes of use, recipient categories, retention timelines, and user controls.
- Audited the submitted ChatGPT App remote MCP profile and confirmed it exposes only the five review-safe tools: list_traditions, get_tradition_guide, search_traditions, compose_prompt_from_design, and evaluate_artwork.
- Removed unnecessary local path and diagnostic metadata from remote tool responses.
- Confirmed the submitted profile does not expose generation, image upload, pixel reading, redraw, inpaint, archive, sync, admin, or filesystem-writing tools.

Privacy policy URL:
<insert published URL>

We will resubmit the app from the OpenAI Platform dashboard.

Best,
Haorui Yu
```
6 changes: 6 additions & 0 deletions docs/platform/chatgpt-remote-mcp-prototype.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ Use `http://127.0.0.1:8765/mcp` for local API experiments. ChatGPT developer mod

- Do not pass private images to a remote server without explicit user approval.
- Do not pass private project paths to a remote server unless the path is inside `VULCA_REMOTE_WORKSPACE_ROOT`.
- Do not echo local filesystem paths in remote tool responses.
- Do not return diagnostic metadata such as request IDs, trace IDs, session IDs, timestamps, or latency measurements unless required for the user's request.
- Do not enable pixel-reading or provider-backed VLM evaluation by default.
- Do not expose filesystem-writing tools in the first prototype.
- Keep all cost-incurring tools behind explicit opt-in.

Published app submissions should use `docs/platform/chatgpt-app-privacy-policy.md`
as the privacy-policy source of truth and should verify raw MCP responses against
`docs/platform/chatgpt-app-resubmission-checklist.md` before resubmission.
2 changes: 2 additions & 0 deletions docs/platform/openai-codex-mcp-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ Before public install instructions:
- validate the repo marketplace in a clean Codex Desktop session;
- verify `vulca-mcp` is available in the target environment;
- verify `vulca-mcp-remote` starts with `VULCA_REMOTE_WORKSPACE_ROOT` set before ChatGPT remote MCP experiments;
- publish and submit the privacy policy in `docs/platform/chatgpt-app-privacy-policy.md`;
- audit the raw remote MCP responses against `docs/platform/chatgpt-app-resubmission-checklist.md`;
- run one no-cost `/visual-discovery` or prompt-composition workflow;
- confirm generated artifacts stay in the workspace;
- confirm public copy says official Codex public publishing is still pending unless OpenAI has opened it.
2 changes: 2 additions & 0 deletions docs/platform/release-readiness-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ Observed: 14 passed.
- Optional: run a full interactive `claude --plugin-dir .` session if you want UI-level confirmation beyond `plugin validate` and non-interactive skill discovery.
- Optional: open Codex UI and confirm the newly added `vulca-plugins` marketplace source appears as expected.
- Deploy `vulca-mcp-remote` behind HTTPS/auth/logging before connecting it to ChatGPT developer mode from a public URL.
- For ChatGPT App resubmission, publish `docs/platform/chatgpt-app-privacy-policy.md`
at a stable public URL and complete `docs/platform/chatgpt-app-resubmission-checklist.md`.
- Review marketplace copy and screenshots before submission.
- Dogfood v0.22 redraw on representative real images and confirm the user-facing after-image is `source_pasteback_path`.
- Decide what to do with main-worktree untracked generated artifacts before any broad cleanup.
13 changes: 11 additions & 2 deletions src/vulca/mcp_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ async def _remote_compose_prompt_from_design(design_path: str) -> dict:
)
from vulca.mcp_server import compose_prompt_from_design

return await compose_prompt_from_design(str(safe_path))
result = await compose_prompt_from_design(str(safe_path))
# The local tool returns the source path for agent debugging. The public
# remote profile should not echo local filesystem paths back to ChatGPT.
result.pop("source_design_path", None)
return result


async def _evaluate_artwork(**kwargs) -> dict:
Expand All @@ -86,14 +90,19 @@ async def _remote_evaluate_artwork(
intent: str = "",
) -> dict:
"""Use this when returning Vulca's L1-L5 rubric without reading pixels or calling a VLM."""
return await _evaluate_artwork(
result = await _evaluate_artwork(
image_path=image_path,
tradition=tradition,
intent=intent,
mock=True,
mode="rubric_only",
vlm_model="",
)
# Keep remote responses purpose-bound: do not echo user file paths or
# diagnostic timing metadata in the submitted ChatGPT app profile.
result.pop("image_path", None)
result.pop("latency_ms", None)
return result


remote_mcp = FastMCP(
Expand Down
37 changes: 36 additions & 1 deletion tests/test_mcp_remote_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,49 @@ def test_remote_workspace_path_allows_relative_file_inside_root(tmp_path):
) == design_path.resolve()


def test_remote_compose_prompt_does_not_echo_source_path(monkeypatch, tmp_path):
from vulca import mcp_remote

workspace = tmp_path / "workspace"
workspace.mkdir()
design_path = workspace / "design.md"
design_path.write_text("# Design\n", encoding="utf-8")

async def fake_compose_prompt_from_design(path):
return {
"composed_prompt": "misty mountain",
"negative_prompt": "",
"source_design_path": path,
}

monkeypatch.setenv("VULCA_REMOTE_WORKSPACE_ROOT", str(workspace))
monkeypatch.setattr(
"vulca.mcp_server.compose_prompt_from_design",
fake_compose_prompt_from_design,
)

result = asyncio.run(
mcp_remote._remote_compose_prompt_from_design("design.md")
)

assert result == {
"composed_prompt": "misty mountain",
"negative_prompt": "",
}


def test_remote_evaluate_artwork_forces_mock_rubric_only(monkeypatch):
from vulca import mcp_remote

captured: dict[str, object] = {}

async def fake_evaluate_artwork(**kwargs):
captured.update(kwargs)
return {"ok": True}
return {
"ok": True,
"image_path": kwargs["image_path"],
"latency_ms": 12,
}

monkeypatch.setattr(mcp_remote, "_evaluate_artwork", fake_evaluate_artwork)

Expand Down