v0.2.0 Design: ChatGPT Read MCP + ActualCoder¶
Historical v0.2 design document. It records an earlier product boundary and is not the current v0.5.0 capability matrix. See Architecture, Security, and v0.5.0 release notes for current behavior.
Product goal¶
v0.2 keeps the normal ChatGPT integration read-only on personal Pro, and adds ActualCoder, an agent-neutral local coding layer that can hand managed worktrees to Codex CLI, GitHub Copilot CLI, or future coding agents.
The GitLab/worktree machinery is deliberately separated from the coding model/backend. This gives the maximum practical capability without requiring a Business workspace or OpenAI model API billing from this project.
Normal ChatGPT Pro
│
├── read/search GitLab via MCP
├── architecture review
├── MR / CI diagnosis
└── define the coding task
│
▼
Codex CLI ───────┐
Copilot CLI ─────┼──► ActualCoder
future agents ───┘ │
▼
gitlab-agent
│
├── create/recover isolated worktree
├── read/write/apply patch
├── run allowlisted build/tests
├── inspect diff
├── commit
├── push / push-update
└── create/recover GitLab MR workflow
Hard requirement: zero OpenAI model API usage¶
The v0.2 project code must not call OpenAI model APIs.
Specifically:
- no
openaiPython dependency; - no calls to
/v1/responses, Chat Completions, embeddings, image APIs, etc.; - the local coding engine does not require
OPENAI_API_KEY; - Codex should be signed in with the user's ChatGPT subscription rather than an API key when avoiding API billing;
CONTROL_PLANE_API_KEYremains a tunnel runtime credential used bytunnel-client, not bygitlab-agent.
CI checks project code for accidental OpenAI model API usage.
v0.2 components¶
1. Existing read-only MCP¶
server.py remains the ChatGPT-facing read MCP.
It exposes:
- repository/file reads;
- project code search;
- merge request metadata/diffs;
- pipelines/jobs/logs.
No MCP write tools are added for the personal-Pro workflow.
2. ActualCoder + local package gitlab_agent¶
The package under src/gitlab_agent/ contains:
config.py— local settings and safety policy;workspace.py— repository cache, worktrees, file edits, Git commit/push/MR flow;runner.py— structured build/test command runner;cli.py— shared JSON-oriented command implementation;actual-coder_cli.py— agent-neutralactual-coderentry point.
Installed commands:
actual-coder
gitlab-agent
actual-coder is the user-facing orchestration layer. gitlab-agent remains the lower-level GitLab/worktree lifecycle controller.
Workspace model¶
Default root:
~/.local/share/chatgpt-gitlab-mcp/
├── repos/
│ └── <project-key>.git
├── worktrees/
│ └── <workspace-id>/
├── state/
│ └── <workspace-id>.json
└── runner-home/
└── <workspace-id>/
A task gets a unique branch such as:
chatgpt/fix-timeout-a1b2c3d4
The user's normal checkout is never modified.
Safety rules¶
Project boundary¶
By default, v0.2 refuses to create a coding workspace unless:
GITLAB_ALLOWED_PROJECTS=team/project-a,team/project-b
is configured.
This can be disabled only by explicitly setting:
GITLAB_REQUIRE_WRITE_ALLOWLIST=false
Branch boundary¶
Generated coding branches must start with:
chatgpt/
or the configured GITLAB_BRANCH_PREFIX.
The engine never force-pushes and never pushes directly to the base branch.
File boundary¶
All file reads/writes are resolved against the managed worktree. Absolute paths and paths escaping the worktree are rejected.
Command boundary¶
Build/test execution:
- uses
subprocesswithshell=False; - requires a bare executable name;
- uses an executable allowlist;
- fixes the working directory to the selected worktree;
- enforces a timeout;
- caps stdout/stderr;
- removes token/secret/password/API-key environment variables;
- removes
SSH_AUTH_SOCK; - uses an isolated HOME directory.
Default executable allowlist:
python, python3, pytest, uv,
node, npm, pnpm, yarn,
make, cmake, ninja,
cargo, go, mvn, gradle
Not allowed by default:
bash, sh, zsh, curl, ssh, sudo, git
Git is exposed through dedicated higher-level operations instead.
Important: this host runner is not a filesystem/container sandbox. A malicious build script can still attempt to access files on the host by absolute path. Run untrusted repositories in a container/VM.
Git credentials¶
The read MCP keeps:
GITLAB_TOKEN
with recommended scopes:
read_api
read_repository
The local Git engine optionally uses a separate:
GITLAB_GIT_TOKEN
For clone-only operation, read_repository is sufficient.
For push / MR flow, use:
write_repository
If GITLAB_GIT_TOKEN is unset, the CLI falls back to GITLAB_TOKEN.
The token is provided to Git through a temporary GIT_ASKPASS helper and is not stored in the remote URL.
Merge Request creation without broad API scope¶
v0.2 can create an MR on the branch's first push using GitLab push options:
merge_request.create
merge_request.target=<branch>
merge_request.title=<title>
merge_request.description=<description>
This lets the initial workflow use Git-over-HTTP write_repository rather than a broad GitLab api scope.
The push-mr command is intentionally intended for the first push of the feature branch. If you already pushed the branch with gitlab-agent push, create the MR manually or use a later API-based extension with separately reviewed permissions.
CLI workflow¶
Create a workspace:
gitlab-agent create team/project-a \
--base-ref main \
--task fix-timeout
Inspect:
gitlab-agent status <workspace-id>
gitlab-agent read <workspace-id> src/example.py
gitlab-agent diff <workspace-id>
Apply a patch:
cat change.patch | gitlab-agent apply-patch <workspace-id>
Or replace a file:
cat new_file.py | gitlab-agent write <workspace-id> src/new_file.py
Run an allowlisted test/build command:
gitlab-agent run <workspace-id> -- uv run pytest
Commit:
gitlab-agent commit <workspace-id> -m "Fix timeout handling"
Push and create MR:
gitlab-agent push-mr <workspace-id> \
--target main \
--title "Fix timeout handling" \
--description-file mr.md
All commands return JSON so Codex can consume the result reliably.
ActualCoder backend interaction¶
Create a Codex handoff:
actual-coder task team/project-a --agent codex --task fix-timeout --goal "Fix the timeout bug"
Or hand the same workflow to GitHub Copilot CLI:
actual-coder task team/project-a --agent copilot --task fix-timeout --goal "Fix the timeout bug"
Coding backends may inspect/edit the returned worktree directly. ActualCoder and gitlab-agent provide a consistent lifecycle, project allowlist, branch policy, test/diff review path, safe push/MR creation, MR iteration, and MR/branch recovery.
Deliberately deferred¶
v0.2 does not implement:
- merge MR;
- approve MR;
- force push;
- delete remote branches;
- direct push to default branch;
- CI/CD variable writes;
- secret management;
- arbitrary shell;
- production deployment actions.
Future path¶
If personal ChatGPT later supports custom MCP write actions, the same WorkspaceManager and CommandRunner can be exposed as MCP tools without redesigning the backend.